查看 RecyclerView 项目的模型
View models for RecyclerView items
我的 activity 有一个 Google 的 ViewModel 可以获取一些模型项。然后将这些项目转换为 RecyclerView 的适配器项目。一个RecyclerView支持的适配器item也有很多种
我想为这些模型对象中的每一个创建单独的视图模型对象,以便我可以仅在该 "small" 视图模型中封装更复杂的逻辑。
目前,当我有一些仅与某些适配器项相关的异步逻辑(需要在 onCleared() 中停止)时,我必须以某种方式通过主视图模型路由回调,以便正确取消注册所有内容。
我正在考虑使用 ViewModelProvider::get(key, modelClass)
,但我的物品会随着时间的推移而变化,我找不到很好的方法来处理 "clear" 旧物品。
您如何处理项目中的这些情况?
编辑:添加更多关于我的问题的信息,也许换句话说:我希望我的 "small" ViewModel 与它所代表的模型项一样长。这意味着:
- 我必须在这些项目的父项接收的相同场景中接收 onCleared() 回调
- 我必须在项目不再
时接收 onCleared() 回调
编辑:请尝试将它与将片段作为项目的 ViewPager 进行比较。每个单独的模型项都表示为一个片段及其 ViewModel。除了 RecyclerView,我想实现类似的东西。
androidx.lifecycle.ViewModel 默认不用于 RecyclerView 项目
为什么?
ViewModel
is AAC (Android 架构组件) 其唯一目的是在 Android [= 的配置更改后继续存在133=] 生命周期,以便在这种情况下可以通过 ViewModel 持久化数据。
这是通过在与托管相关的存储中缓存 VM 实例来实现的 activity。
这就是为什么它不应该在 RecyclerView (ViewHolder) 项目 直接 上使用,因为项目视图本身将是 Activity/Fragment 并且它 (RecyclerView/ViewHolder) 不包含任何特定的 API 来提供 ViewModelStoreOwner
(从哪个 ViewModels基本上是针对给定的 Activity/Fragment 实例派生的).
获取 ViewModel 的简单语法是:
ViewModelProvider(this).get(ViewModel::class.java)
& 此处 this
将引用 Activity/Fragment 上下文。
所以即使你最终在 RecyclerView
项目中使用 ViewModel
,它也会给你相同的实例,因为上下文可能是 Activity/Fragment 在 RecyclerView 中是相同的对我来说没有意义。所以 ViewModel 对 RecyclerView 没用,或者对这种情况影响不大。
TL;DR
解决方案?
你可以直接传入你Activity/Fragment的ViewModel
需要观察的LiveData
对象到你的RecyclerView.Adapter
class。您还需要为适配器提供 LifecycleOwner
以开始观察给定的实时数据。
因此您的适配器 class 将如下所示:
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
class 上使用它,那么您可以在 onCreateViewHolder
方法期间将 LiveData
对象传递给您的 ViewHolder 实例连同 lifecycleOwner
.
加分!
如果您在 RecyclerView 项目上使用数据绑定,那么您可以轻松地从绑定 class 中获取 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
实例使用 wrapper class 来为你提供开箱即用的 LiveData
但如果 wrapper class 是扩展 ViewModel
class.
一旦担心模仿 ViewModel
的 onCleared()
方法,您可以在包装器 class 上创建一个方法,当 ViewHolder
被回收或分离时调用该方法来自 window 通过方法 onViewRecycled()
or onViewDetachedFromWindow()
最适合您的情况。
编辑 @Mariusz 的评论:关注使用 Activity/Fragment 作为 LifecycleOwner 是正确的。但是读成POC会有一点误会。
一旦使用 lifecycleOwner
观察给定 RecyclerViewHolder
项中的 LiveData
,就可以这样做,因为 LiveData
是生命周期感知组件,它在内部处理对生命周期的订阅,因此可以安全使用。即使您可以根据需要明确删除观察,也可以使用 onViewRecycled()
或 onViewDetachedFromWindow()
方法。
关于内部异步操作ViewHolder
:
如果您正在使用协程,那么您可以使用 lifecycleOwner
中的 lifecycleScope
来调用您的操作,然后将数据提供回特定观察 LiveData
而无需明确处理清除案例 (LifecycleScope
会为您处理).
如果不使用协同程序,那么您仍然可以进行异步调用并将数据提供回观察 LiveData
并且不用担心在 onViewRecycled()
或 onViewDetachedFromWindow()
回调。这里重要的是 LiveData
,它尊重给定 LifecycleOwner
的生命周期,而不是正在进行的异步操作。
尽管 Android 在 Android 架构组件 中使用 ViewModels 是正确的,但这并不意味着它们只是 AAC 的一部分。事实上,ViewModels 是 MVVM Architecture Pattern 的组件之一,它不仅与 Android 相关。所以 ViewModel 的实际目的是 而不是 以在 Android 的 生命周期 中保存数据变化。但是,由于在没有 View 引用的情况下公开其数据,因此非常适合 Android 特定情况,其中 View可以在不影响保持其状态的组件(ViewModel)的情况下重新创建。尽管如此,它还有其他好处,例如促进 关注点分离 等。
同样重要的是要提到你的案例与 ViewPager-Fragments 案例相比不能 100%,因为主要区别在于 ViewHolders 将在物品之间 回收利用 。即使 ViewPager 的 Fragments 被销毁并重新创建,它们仍然会代表相同的 Fragment相同的数据。这就是为什么他们可以安全地绑定现有 ViewModel
提供的数据。但是,在 ViewHolder
的情况下,当它被重新创建时,它可能代表一个全新的项目,因此它假设的 ViewModel
可能提供的数据可能不正确,引用了旧项目。
话虽如此,您可以轻松地将 ViewHolder
变成 ViewModelStoreOwner
:
class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), ViewModelStoreOwner {
private var viewModelStore: ViewModelStore = ViewModelStore()
override fun getViewModelStore(): ViewModelStore = viewModelStore
}
如果 ViewModel
提供的数据与 ViewHolder
的项目无关(所有项目之间共享状态),这仍然有用。但是,如果不是这种情况,那么您需要通过调用 viewModelStore.clear()
使 ViewModelStore
无效,并可能在 ViewHolder
的 [=22] 中创建一个新的 ViewModel
实例=].无论 view 的 lifecycle,你都会失去保持状态的优势,但有时仍然有用,因为遵循 关注点分离.
最后,关于使用LiveData
实例来控制状态的选项,无论它是由ViewHolder
的共享的还是特定的ViewModel
提供的,还是它通过 Adapter
传递,您将需要一个 LifecycleOwner
来观察它。使用当前 Fragment
或 Activity
生命周期的更好方法是仅使用特定 ViewHolder
的实际生命周期,因为它们实际上是创建和销毁的,方法是让它们实现 LifecycleOwner
界面。我创建了一个小的 library,它就是这样做的。
不知道 google 是否对嵌套 ViewModel 有很好的支持,看起来好像没有。
值得庆幸的是,我们不需要坚持 androidx.lifecycle.ViewModel
在我们需要的地方应用 MVVM 方法。我决定写一个小例子:
片段,没有变化:
@Override public void onCreate(@Nullable Bundle savedInstanceState) {
final ItemListAdapter adapter = new ItemListAdapter();
binding.getRoot().setAdapter(adapter);
viewModel = new ViewModelProvider(this).get(ItemListViewModel.class);
viewModel.getItems().observe(getViewLifecycleOwner(), adapter::submitList);
}
ItemListAdapter,除了填充视图之外,它还负责通知项目的观察者——他们是否应该继续收听。在我的示例中,适配器是扩展 RecyclerView.Adapter 的 ListAdapter,因此它接收项目列表。这是无意的,只是编辑了一些我已有的代码。使用不同的基础实现可能会好得多,但出于演示目的是可以接受的:
@Override public Holder onCreateViewHolder(ViewGroup parent, int viewType) {
return new Holder(parent);
}
@Override public void onBindViewHolder(Holder holder, int position) {
holder.lifecycle.setCurrentState(Lifecycle.State.RESUMED);
holder.bind(getItem(position));
}
@Override public void onViewRecycled(Holder holder) {
holder.lifecycle.setCurrentState(Lifecycle.State.DESTROYED);
}
// Idk, but these both may be used to pause/resume, while bind/recycle for start/stop.
@Override public void onViewAttachedToWindow(Holder holder) { }
@Override public void onViewDetachedFromWindow(Holder holder) { }
Holder. 它实现了 LifecycleOwner,它允许自动取消订阅,只是从 androidx.activity.ComponentActivity
来源复制所以一切都应该没问题 :D :
static class Holder extends RecyclerView.Holder implements LifecycleOwner {
/*pkg*/ LifecycleRegistry lifecycle = new LifecycleRegistry(this);
/*pkg*/ Holder(ViewGroup parent) { /* creating holder using parent's context */ }
/*pkg*/ void bind(ItemViewModel viewModel) {
viewModel.getItem().observe(this, binding.text1::setText);
}
@Override public Lifecycle getLifecycle() { return lifecycle; }
}
List view-model,“classique”androidx-ish ViewModel,但是很粗糙,也提供嵌套视图模型。请注意,在此示例中,所有视图模型在构造函数中立即开始运行,直到父视图模型被命令清除!不要在家里尝试这个!
public class ItemListViewModel extends ViewModel {
private final MutableLiveData<List<ItemViewModel>> items = new MutableLiveData<>();
public ItemListViewModel() {
final List<String> list = Items.getInstance().getItems();
// create "nested" view-models which start background job immediately
final List<ItemViewModel> itemsViewModels = list.stream()
.map(ItemViewModel::new)
.collect(Collectors.toList());
items.setValue(itemsViewModels);
}
public LiveData<List<ItemViewModel>> getItems() { return items; }
@Override protected void onCleared() {
// need to clean nested view-models, otherwise...
items.getValue().stream().forEach(ItemViewModel::cancel);
}
}
Item 的视图模型,使用一些 rxJava 来模拟一些后台工作和更新。我有意不将其实现为 androidx....ViewModel
,只是为了强调视图模型不是 google 命名 ViewModel 的名称,而是作为视图模型的行为。但在实际程序中,它很可能会扩展:
// Wow, we can implement ViewModel without androidx.lifecycle.ViewModel, that's cool!
public class ItemViewModel {
private final MutableLiveData<String> item = new MutableLiveData<>();
private final AtomicReference<Disposable> work = new AtomicReference<>();
public ItemViewModel(String topicInitial) {
item.setValue(topicInitial);
// start updating ViewModel right now :D
DisposableHelper.set(work, Observable
.interval((long) (Math.random() * 5 + 1), TimeUnit.SECONDS)
.map(i -> topicInitial + " " + (int) (Math.random() * 100) )
.subscribe(item::postValue));
}
public LiveData<String> getItem() { return item; }
public void cancel() {
DisposableHelper.dispose(work);
}
}
几个注释,在这个示例中:
- “父”ViewModel 存在于 activity 范围内,因此它的所有数据(嵌套视图模型)也是如此。
- 在此示例中,所有 嵌套虚拟机立即开始运行。这不是我们想要的。我们想相应地修改constructors, onBind, onRecycle 和相关的方法。
- 请测试内存泄漏。
我遵循了 aeracode 的这个精彩答案 ,但有一个例外。我使用了非常适合我的 Rx BehaviourSubject 而不是 ViewModel
。
如果是协同程序,您可以选择使用 StateFlow
.
clas MyFragment: Fragment(){
private val listSubject = BehaviorSubject.create<List<Items>>()
...
private fun observeData() {
viewModel.listLiveData.observe(viewLifecycleOwner) { list ->
listSubject.onNext(list)
}
}
}
RecyclerView
class MyAdapter(
private val listObservable: BehaviorSubject<List<Items>>
) : RecyclerView.Adapter<MyViewHolder>() {
[...]
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.bindToData(getItem(position))
}
override fun onViewRecycled(holder: MyViewHolder) {
holder.onViewRecycled()
}
...
class MyViewHolder(val binding: LayoutBinding) :
RecyclerView.ViewHolder(binding.root) {
private var disposable: Disposable? = null
fun bindToData(item: Item) = with(binding) {
titleTv.text = item.title
disposable = listObservable.subscribe(::setItemList) <- Here You listen
}
fun onViewRecycled() {
disposable?.dispose()
}
}
我的 activity 有一个 Google 的 ViewModel 可以获取一些模型项。然后将这些项目转换为 RecyclerView 的适配器项目。一个RecyclerView支持的适配器item也有很多种
我想为这些模型对象中的每一个创建单独的视图模型对象,以便我可以仅在该 "small" 视图模型中封装更复杂的逻辑。
目前,当我有一些仅与某些适配器项相关的异步逻辑(需要在 onCleared() 中停止)时,我必须以某种方式通过主视图模型路由回调,以便正确取消注册所有内容。
我正在考虑使用 ViewModelProvider::get(key, modelClass)
,但我的物品会随着时间的推移而变化,我找不到很好的方法来处理 "clear" 旧物品。
您如何处理项目中的这些情况?
编辑:添加更多关于我的问题的信息,也许换句话说:我希望我的 "small" ViewModel 与它所代表的模型项一样长。这意味着:
- 我必须在这些项目的父项接收的相同场景中接收 onCleared() 回调
- 我必须在项目不再 时接收 onCleared() 回调
编辑:请尝试将它与将片段作为项目的 ViewPager 进行比较。每个单独的模型项都表示为一个片段及其 ViewModel。除了 RecyclerView,我想实现类似的东西。
androidx.lifecycle.ViewModel 默认不用于 RecyclerView 项目
为什么?
ViewModel
is AAC (Android 架构组件) 其唯一目的是在 Android [= 的配置更改后继续存在133=] 生命周期,以便在这种情况下可以通过 ViewModel 持久化数据。
这是通过在与托管相关的存储中缓存 VM 实例来实现的 activity。
这就是为什么它不应该在 RecyclerView (ViewHolder) 项目 直接 上使用,因为项目视图本身将是 Activity/Fragment 并且它 (RecyclerView/ViewHolder) 不包含任何特定的 API 来提供 ViewModelStoreOwner
(从哪个 ViewModels基本上是针对给定的 Activity/Fragment 实例派生的).
获取 ViewModel 的简单语法是:
ViewModelProvider(this).get(ViewModel::class.java)
& 此处 this
将引用 Activity/Fragment 上下文。
所以即使你最终在 RecyclerView
项目中使用 ViewModel
,它也会给你相同的实例,因为上下文可能是 Activity/Fragment 在 RecyclerView 中是相同的对我来说没有意义。所以 ViewModel 对 RecyclerView 没用,或者对这种情况影响不大。
TL;DR
解决方案?
你可以直接传入你Activity/Fragment的ViewModel
需要观察的LiveData
对象到你的RecyclerView.Adapter
class。您还需要为适配器提供 LifecycleOwner
以开始观察给定的实时数据。
因此您的适配器 class 将如下所示:
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
class 上使用它,那么您可以在 onCreateViewHolder
方法期间将 LiveData
对象传递给您的 ViewHolder 实例连同 lifecycleOwner
.
加分!
如果您在 RecyclerView 项目上使用数据绑定,那么您可以轻松地从绑定 class 中获取 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
实例使用 wrapper class 来为你提供开箱即用的 LiveData
但如果 wrapper class 是扩展 ViewModel
class.
一旦担心模仿 ViewModel
的 onCleared()
方法,您可以在包装器 class 上创建一个方法,当 ViewHolder
被回收或分离时调用该方法来自 window 通过方法 onViewRecycled()
or onViewDetachedFromWindow()
最适合您的情况。
编辑 @Mariusz 的评论:关注使用 Activity/Fragment 作为 LifecycleOwner 是正确的。但是读成POC会有一点误会。
一旦使用 lifecycleOwner
观察给定 RecyclerViewHolder
项中的 LiveData
,就可以这样做,因为 LiveData
是生命周期感知组件,它在内部处理对生命周期的订阅,因此可以安全使用。即使您可以根据需要明确删除观察,也可以使用 onViewRecycled()
或 onViewDetachedFromWindow()
方法。
关于内部异步操作ViewHolder
:
如果您正在使用协程,那么您可以使用
lifecycleOwner
中的lifecycleScope
来调用您的操作,然后将数据提供回特定观察LiveData
而无需明确处理清除案例 (LifecycleScope
会为您处理).如果不使用协同程序,那么您仍然可以进行异步调用并将数据提供回观察
LiveData
并且不用担心在onViewRecycled()
或onViewDetachedFromWindow()
回调。这里重要的是LiveData
,它尊重给定LifecycleOwner
的生命周期,而不是正在进行的异步操作。
尽管 Android 在 Android 架构组件 中使用 ViewModels 是正确的,但这并不意味着它们只是 AAC 的一部分。事实上,ViewModels 是 MVVM Architecture Pattern 的组件之一,它不仅与 Android 相关。所以 ViewModel 的实际目的是 而不是 以在 Android 的 生命周期 中保存数据变化。但是,由于在没有 View 引用的情况下公开其数据,因此非常适合 Android 特定情况,其中 View可以在不影响保持其状态的组件(ViewModel)的情况下重新创建。尽管如此,它还有其他好处,例如促进 关注点分离 等。
同样重要的是要提到你的案例与 ViewPager-Fragments 案例相比不能 100%,因为主要区别在于 ViewHolders 将在物品之间 回收利用 。即使 ViewPager 的 Fragments 被销毁并重新创建,它们仍然会代表相同的 Fragment相同的数据。这就是为什么他们可以安全地绑定现有 ViewModel
提供的数据。但是,在 ViewHolder
的情况下,当它被重新创建时,它可能代表一个全新的项目,因此它假设的 ViewModel
可能提供的数据可能不正确,引用了旧项目。
话虽如此,您可以轻松地将 ViewHolder
变成 ViewModelStoreOwner
:
class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), ViewModelStoreOwner {
private var viewModelStore: ViewModelStore = ViewModelStore()
override fun getViewModelStore(): ViewModelStore = viewModelStore
}
如果 ViewModel
提供的数据与 ViewHolder
的项目无关(所有项目之间共享状态),这仍然有用。但是,如果不是这种情况,那么您需要通过调用 viewModelStore.clear()
使 ViewModelStore
无效,并可能在 ViewHolder
的 [=22] 中创建一个新的 ViewModel
实例=].无论 view 的 lifecycle,你都会失去保持状态的优势,但有时仍然有用,因为遵循 关注点分离.
最后,关于使用LiveData
实例来控制状态的选项,无论它是由ViewHolder
的共享的还是特定的ViewModel
提供的,还是它通过 Adapter
传递,您将需要一个 LifecycleOwner
来观察它。使用当前 Fragment
或 Activity
生命周期的更好方法是仅使用特定 ViewHolder
的实际生命周期,因为它们实际上是创建和销毁的,方法是让它们实现 LifecycleOwner
界面。我创建了一个小的 library,它就是这样做的。
不知道 google 是否对嵌套 ViewModel 有很好的支持,看起来好像没有。
值得庆幸的是,我们不需要坚持 androidx.lifecycle.ViewModel
在我们需要的地方应用 MVVM 方法。我决定写一个小例子:
片段,没有变化:
@Override public void onCreate(@Nullable Bundle savedInstanceState) {
final ItemListAdapter adapter = new ItemListAdapter();
binding.getRoot().setAdapter(adapter);
viewModel = new ViewModelProvider(this).get(ItemListViewModel.class);
viewModel.getItems().observe(getViewLifecycleOwner(), adapter::submitList);
}
ItemListAdapter,除了填充视图之外,它还负责通知项目的观察者——他们是否应该继续收听。在我的示例中,适配器是扩展 RecyclerView.Adapter 的 ListAdapter,因此它接收项目列表。这是无意的,只是编辑了一些我已有的代码。使用不同的基础实现可能会好得多,但出于演示目的是可以接受的:
@Override public Holder onCreateViewHolder(ViewGroup parent, int viewType) {
return new Holder(parent);
}
@Override public void onBindViewHolder(Holder holder, int position) {
holder.lifecycle.setCurrentState(Lifecycle.State.RESUMED);
holder.bind(getItem(position));
}
@Override public void onViewRecycled(Holder holder) {
holder.lifecycle.setCurrentState(Lifecycle.State.DESTROYED);
}
// Idk, but these both may be used to pause/resume, while bind/recycle for start/stop.
@Override public void onViewAttachedToWindow(Holder holder) { }
@Override public void onViewDetachedFromWindow(Holder holder) { }
Holder. 它实现了 LifecycleOwner,它允许自动取消订阅,只是从 androidx.activity.ComponentActivity
来源复制所以一切都应该没问题 :D :
static class Holder extends RecyclerView.Holder implements LifecycleOwner {
/*pkg*/ LifecycleRegistry lifecycle = new LifecycleRegistry(this);
/*pkg*/ Holder(ViewGroup parent) { /* creating holder using parent's context */ }
/*pkg*/ void bind(ItemViewModel viewModel) {
viewModel.getItem().observe(this, binding.text1::setText);
}
@Override public Lifecycle getLifecycle() { return lifecycle; }
}
List view-model,“classique”androidx-ish ViewModel,但是很粗糙,也提供嵌套视图模型。请注意,在此示例中,所有视图模型在构造函数中立即开始运行,直到父视图模型被命令清除!不要在家里尝试这个!
public class ItemListViewModel extends ViewModel {
private final MutableLiveData<List<ItemViewModel>> items = new MutableLiveData<>();
public ItemListViewModel() {
final List<String> list = Items.getInstance().getItems();
// create "nested" view-models which start background job immediately
final List<ItemViewModel> itemsViewModels = list.stream()
.map(ItemViewModel::new)
.collect(Collectors.toList());
items.setValue(itemsViewModels);
}
public LiveData<List<ItemViewModel>> getItems() { return items; }
@Override protected void onCleared() {
// need to clean nested view-models, otherwise...
items.getValue().stream().forEach(ItemViewModel::cancel);
}
}
Item 的视图模型,使用一些 rxJava 来模拟一些后台工作和更新。我有意不将其实现为 androidx....ViewModel
,只是为了强调视图模型不是 google 命名 ViewModel 的名称,而是作为视图模型的行为。但在实际程序中,它很可能会扩展:
// Wow, we can implement ViewModel without androidx.lifecycle.ViewModel, that's cool!
public class ItemViewModel {
private final MutableLiveData<String> item = new MutableLiveData<>();
private final AtomicReference<Disposable> work = new AtomicReference<>();
public ItemViewModel(String topicInitial) {
item.setValue(topicInitial);
// start updating ViewModel right now :D
DisposableHelper.set(work, Observable
.interval((long) (Math.random() * 5 + 1), TimeUnit.SECONDS)
.map(i -> topicInitial + " " + (int) (Math.random() * 100) )
.subscribe(item::postValue));
}
public LiveData<String> getItem() { return item; }
public void cancel() {
DisposableHelper.dispose(work);
}
}
几个注释,在这个示例中:
- “父”ViewModel 存在于 activity 范围内,因此它的所有数据(嵌套视图模型)也是如此。
- 在此示例中,所有 嵌套虚拟机立即开始运行。这不是我们想要的。我们想相应地修改constructors, onBind, onRecycle 和相关的方法。
- 请测试内存泄漏。
我遵循了 aeracode 的这个精彩答案 ViewModel
。
如果是协同程序,您可以选择使用 StateFlow
.
clas MyFragment: Fragment(){
private val listSubject = BehaviorSubject.create<List<Items>>()
...
private fun observeData() {
viewModel.listLiveData.observe(viewLifecycleOwner) { list ->
listSubject.onNext(list)
}
}
}
RecyclerView
class MyAdapter(
private val listObservable: BehaviorSubject<List<Items>>
) : RecyclerView.Adapter<MyViewHolder>() {
[...]
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.bindToData(getItem(position))
}
override fun onViewRecycled(holder: MyViewHolder) {
holder.onViewRecycled()
}
...
class MyViewHolder(val binding: LayoutBinding) :
RecyclerView.ViewHolder(binding.root) {
private var disposable: Disposable? = null
fun bindToData(item: Item) = with(binding) {
titleTv.text = item.title
disposable = listObservable.subscribe(::setItemList) <- Here You listen
}
fun onViewRecycled() {
disposable?.dispose()
}
}