android - 查看 Recycler 的模型查看项目
问题描述
我的活动有一个谷歌的 ViewModel 来获取一些模型项目。然后将这些项目转换为 RecyclerView 的适配器项目。一个 RecyclerView 还支持多种类型的适配器项。
我想为这些模型对象中的每一个拥有单独的视图模型对象,以便我可以将更复杂的逻辑封装在那个“小”视图模型中。
目前,当我有一些仅与某些适配器项相关的异步逻辑(需要在 onCleared() 中停止)时,我必须以某种方式通过主视图模型路由回调,以便正确取消注册所有内容。
我正在考虑使用ViewModelProvider::get(key, modelClass)
,但我的物品会随着时间的推移而变化,我找不到“清除”旧物品的好方法。
您如何在项目中处理这些案例?
编辑:要添加有关我的关注的更多信息,也许用不同的词:我希望我的“小” ViewModel 与它所代表的模型项一样长。代表着:
- 我必须在这些项目的父项接收的相同场景中接收 onCleared() 回调
- 当项目不再存在时,我必须收到 onCleared() 回调
编辑:请尝试将其与以片段作为项目的 ViewPager 进行比较。每个单独的模型项都表示为带有其 ViewModel 的片段。我想实现类似的东西,但对于 RecyclerView。
解决方案
默认情况下, androidx.lifecycle.ViewModel并不打算用于 RecyclerView 项目
为什么?
ViewModel
是 AAC (Android 架构组件) ,其唯一目的是在 Android Activity/Fragment生命周期的配置更改中幸存下来,以便在这种情况下可以通过 ViewModel 持久化数据。
这是通过在与托管活动相关的存储中缓存 VM 实例来实现的。
这就是为什么不应该直接在 RecyclerView (ViewHolder)项目上使用它的原因,因为项目视图本身将是 Activity/Fragment 的一部分,并且它(RecyclerView/ViewHolder)不包含要提供的任何特定 API (ViewModel 基本上是从中派生的对于给定的 Activity/Fragment 实例)。ViewModelStoreOwner
获取 ViewModel 的简单语法是:
ViewModelProvider(this).get(ViewModel::class.java)
& 这里this
将被称为 Activity/Fragment 上下文。
因此,即使您最终ViewModel
在RecyclerView
Items 中使用,它也会给您相同的实例,因为上下文可能是 Activity/Fragment 在 RecyclerView 中是相同的,这对我来说没有意义。所以 ViewModel 对 RecyclerView 没用,或者它对这种情况没有多大贡献。
TL;博士
解决方案?
您可以直接传入LiveData
您需要从课堂ViewModel
中的 Activity/Fragment 观察的对象RecyclerView.Adapter
。您还需要提供LifecycleOwner
适配器以开始观察给定的实时数据。
因此,您的 Adapter 类将如下所示:
class RecyclerViewAdapter(private val liveDataToObserve: LiveData<T>, private val lifecycleOwner: LifecycleOwner) : RecyclerView.Adapter<ViewHolder>() {
init {
liveDataToObserve.observe(lifecycleOwner) { t ->
// Notify data set or something...
}
}
}
如果不是这种情况,并且您希望将它放在ViewHolder
课堂上,那么您可以在方法LiveData
期间将您的对象onCreateViewHolder
与lifecycleOwner
.
加分!
如果您在 RecyclerView 项目上使用数据绑定,那么您可以轻松地lifecyclerOwner
从绑定类中获取对象。您需要做的就是在onCreateViewHolder()
下面设置它:
class RecyclerViewAdapter(private val liveDataToObserve: LiveData<T>, private val lifecycleOwner: LifecycleOwner) : RecyclerView.Adapter<ViewHolder>() {
override fun onCreateViewHolder: ViewHolder {
// Some piece of code for binding
binding.lifecycleOwner = this@RecyclerViewAdapter.lifecycleOwner
// Another piece of code and return viewholder
}
}
class ViewHolder(private val someLiveData: LiveData<T>, binding: ViewDataBinding): RecyclerView.ViewHolder(binding.root) {
init {
someLiveData.observe(requireNotNull(binding.lifecycleOwner)) { t->
// set your UI by live data changes here
}
}
}
所以是的,您可以为您的ViewHolder
实例使用包装类来为您提供LiveData
开箱即用的功能,但如果包装类正在扩展ViewModel
类,我会不鼓励它。
只要担心模仿onCleared()
的方法ViewModel
,您就可以在包装类上创建一个方法,该方法在ViewHolder
被回收或通过方法onViewRecycled()
或onViewDetachedFromWindow()
最适合您的情况的任何方法从窗口分离时被调用。
编辑@Mariusz 的评论:关于使用Activity/Fragment作为LifecycleOwner的担忧是正确的。但将其解读为 POC 可能会产生轻微的误解。
只要有人在给定项目lifecycleOwner
中观察,就可以这样做,因为它是生命周期感知组件,它在内部处理对生命周期的订阅,因此可以安全使用。即使您可以根据需要显式删除观察,也可以使用or方法。LiveData
RecyclerViewHolder
LiveData
onViewRecycled()
onViewDetachedFromWindow()
关于里面的异步操作ViewHolder
:
如果您正在使用协程,那么您可以使用
lifecycleScope
fromlifecycleOwner
来调用您的操作,然后将数据提供回特定的观察LiveData
,而无需明确处理清除案例(LifecycleScope
将为您处理它)。如果不使用协程,那么您仍然可以进行异步调用并将数据返回给观察者,而
LiveData
不必担心在onViewRecycled()
或onViewDetachedFromWindow()
回调期间清除异步操作。这里重要的是LiveData
它尊重 given 的生命周期LifecycleOwner
,而不是正在进行的异步操作。
推荐阅读
- r - 如何约束字符串ggplots和交互生成的格式以在命名颜色向量中查找颜色?
- f# - 何时使用 F# 的 typedefof<'T> 与 typeof<'T>?
- python - 从一些 numpy 数组创建 DataFrame
- matlab - 如何找到最高峰的 x&y 坐标并将数据存储到变量中
- dynamic - 具有动态行高的 SSRS Tablix 控件
- regex - 在 mod_rewrite 中使用有效的正则表达式减少路径
- jquery - VBA 将数据输入到 Jquery 表中以在网站上提交搜索
- f# - 如何使用单个根对简单层次结构建模
- testing - .NET Standard 库的单元测试项目是否应该针对 .NET Core 以外的框架?
- vba - 使用 VBA 设置从 word 到 excel 的文档合并的问题