查看 RecyclerView 项目的模型 [英] View models for RecyclerView items

查看:32
本文介绍了查看 RecyclerView 项目的模型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的活动有一个 Google 的 ViewModel,可以获取一些模型项.然后将这些项目转换为 RecyclerView 的适配器项目.一个 RecyclerView 还支持多种类型的适配器项.

My activity has a Google's ViewModel that fetches some model items. These items are then transformed into adapter items of a RecyclerView. There are also many types of adapter items supported by one RecyclerView.

我希望为这些模型对象中的每一个都有单独的视图模型对象,以便我可以将更复杂的逻辑封装在那个小"视图模型中.

I would like to have separate view model object for each of these model objects so that I can have more complex logic encapsulated only within that "small" view model.

目前,当我有一些仅与某些适配器项相关的异步逻辑(需要在 onCleared() 中停止)时,我必须以某种方式通过主视图模型路由回调,以便正确注销所有内容.

Currently when I have some asynchronous logic (that needs to be stopped in onCleared()) that is related only to some adapter item I have to somehow route callbacks through main view model so that everything is properly unregistered.

我正在考虑使用 ViewModelProvider::get(key, modelClass) 但我的项目随着时间的推移而变化,我找不到清除"旧项目的好方法.

I was considering using ViewModelProvider::get(key, modelClass) but my items are changing over time and I can't find a nice way to "clear" old items.

您在项目中如何处理这些案例?

How are you handling these cases in your projects?

要添加有关我关注的更多信息,也许用不同的词:我希望我的小"ViewModel 与它所代表的模型项一样长.这意味着:

To add more information about my concern, maybe in different words: I want my "small" ViewModel to live as long as the model item which it represents. It means that:

  • 在与这些项目的父项接收相同的场景中,我必须接收 onCleared() 回调
  • 当项目不再存在时,我必须接收 onCleared() 回调

请尝试将其与以 Fragments 作为项目的 ViewPager 进行比较.每个单独的模型项都表示为一个带有其 ViewModel 的 Fragment.我想实现类似的东西,但对于 RecyclerView.

Please try to compare it to a ViewPager with Fragments as items. Every individual model item is represented as a Fragment with its ViewModel. I would like achieve something similar but for RecyclerView.

推荐答案

不知道 google 是否对嵌套的 ViewModel 有很好的支持,貌似没有.值得庆幸的是,我们不需要坚持 androidx.lifecycle.ViewModel 在我们需要的地方应用 MVVM 方法.我决定写一个小例子:

Don't know if google has nice support for nested ViewModel's, looks like not. Thankfully, we don't need to stick to androidx.lifecycle.ViewModel to apply MVVM approach where we need. And there is a small example I decided to write:

片段,没有任何变化:

    @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,除了填充视图外,它还负责通知项目的观察者——他们是否继续监听.在我的示例适配器中,ListAdapter 扩展了 RecyclerView.Adapter,因此它接收项目列表.这是无意的,只是编辑了我已有的一些代码.使用不同的基本实现可能会好得多,但用于演示目的是可以接受的:

ItemListAdapter, in addition to populate view, it also becomes responsible for notifying item's observers - should they continue to listen, or not. In my example adapter was ListAdapter which extends RecyclerView.Adapter, so it receives list of items. This is unintentionally, just edited some code I already have. It's probably much better to use different base implementation, but it's acceptable for demonstration purposes:

    @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 :

Holder. It implements LifecycleOwner, which allows to unsubscribe automatically, just copied from androidx.activity.ComponentActivity sources so all should be okay :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; }
}

列表视图模型,经典"androidx-ish ViewModel,但是很粗糙,还提供嵌套的视图模型.请注意,在这个示例中所有视图模型立即开始运行,在构造函数中,直到父视图模型被命令清除!不要在家里尝试这个!

List view-model, "classique" androidx-ish ViewModel, but very rough, also provide nested view models. Please, pay attention, in this sample all view-models start to operate immediately, in constructor, until parent view-model is commanded to clear! Don't Try This at Home!

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,只是为了强调视图模型不是谷歌命名的 ViewModel,而是作为视图模型的行为.但在实际程序中,它很可能会扩展:

Item's view-model, using a bit of rxJava to simulate some background work and updates. Intentionally I do not implement it as androidx....ViewModel, just to highlight that view-model is not what google names ViewModel but what behaves as view-model. In actual program it most likely will extend, though:

// 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);
    }

}

几个注意事项,在此示例中:

Few notes, in this sample:

  • 父母"ViewModel 位于活动范围内,因此它的所有数据(嵌套视图模型)也是如此.
  • 在这个例子中 all 嵌套的 vm 立即开始运行.这不是我们想要的.我们要相应地修改构造函数、onBind、onRecycle 和相关方法.
  • 请测试内存泄漏.
  • "Parent" ViewModel lives in activity scope, so all its data (nested view models) as well.
  • In this example all nested vm start to operate immediately. Which is not what we want. We want to modify constructors, onBind, onRecycle and related methods accordingly.
  • Please, test it on memory leaks.

这篇关于查看 RecyclerView 项目的模型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆