Android架构组件:使用ViewModel for RecyclerView项目

jac*_*ast 24 android mvvm android-recyclerview android-architecture-components

我正在尝试使用Architecture Components,我想为RecyclerView的每个项目构建一个ViewModel.我不确定这是否正式正确或我应该坚持"旧方式".

我有这个适配器:

public class PostAdapter extends RecyclerView.Adapter<PostAdapter.PostViewHolder> {

    private List<Post> list;
    public static class PostViewHolder extends RecyclerView.ViewHolder{
        final ItemPostBinding binding;

        public PostViewHolder(ItemPostBinding binding){
            super(binding.getRoot());
            this.binding = binding;
        }
    }

    @Override
    public PostViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        ItemPostBinding binding = DataBindingUtil
                .inflate(LayoutInflater.from(parent.getContext()), R.layout.item_post,
                        parent, false);


        return new PostViewHolder(binding, parent.getContext());
    }

    @Override
    public void onBindViewHolder(PostViewHolder holder, int position) {
        holder.binding.setPost(list.get(position));
        holder.binding.executePendingBindings();
    }

    @Override
    public int getItemCount() {
        return list == null ? 0 : list.size();
    }

    public void setList(List<Post> list){
        this.list = list;
        notifyDataSetChanged();
    }
}
Run Code Online (Sandbox Code Playgroud)

哪个工作正常,但它非常基本.如何更新它,以便每个项目都有自己的ViewModel关联?甚至可能吗?

编辑:玩它,我试图通过以下方式放入ViewModels:

public class PostAdapter extends RecyclerView.Adapter<PostAdapter.PostViewHolder> {

    private List<Post> list;
    public static class PostViewHolder extends RecyclerView.ViewHolder{
        final ItemPostBinding binding;
        private final Context context;
        private GalleryItemViewModel viewModel;

        public PostViewHolder(ItemPostBinding binding, Context context){
            super(binding.getRoot());
            this.binding = binding;
            this.context = context;
        }

        public Context getContext(){
            return context;
        }

        public void setViewModel(GalleryItemViewModel viewModel){
            this.viewModel = viewModel;
            binding.setViewModel(viewModel);
        }
    }

    @Override
    public PostViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        ItemPostBinding binding = DataBindingUtil
                .inflate(LayoutInflater.from(parent.getContext()), R.layout.item_post,
                        parent, false);


        return new PostViewHolder(binding, parent.getContext());
    }

    @Override
    public void onBindViewHolder(PostViewHolder holder, int position) {
        GalleryItemViewModel vm = ViewModelProviders.of((FragmentActivity) holder.getContext()).get(GalleryItemViewModel.class);
        vm.setPost(list.get(position));
        holder.setViewModel(vm);
    }

    @Override
    public int getItemCount() {
        return list == null ? 0 : list.size();
    }

    public void setList(List<Post> list){
        this.list = list;
        notifyDataSetChanged();
    }
}
Run Code Online (Sandbox Code Playgroud)

它有效,但这是正确的方法吗?

Sta*_*dar 9

有趣,但答案-这是正确的方法,应该接受:)可以清除一些代码并将其GalleryItemViewModel从中删除PostViewHolder,因为您正在创建硬引用而不使用它。然后onBindViewHolder()像这样直接使用holder.binding.setViewModel(vm);

这是MVVM代码示例的链接,可以为您提供帮助。


Thr*_*ian 5

首先,ViewModel 的正确实现应该是通过扩展android.arch.lifecycle.ViewModel. 扩展的示例BaseObservable使 ViewModel 类成为数据类,但它应该是表示类,因为它正在取代 MVP 模式的演示者。

另一件事是ViewModelProviders.of(context).get(Class.class)为每次调用返回相同的 ViewModel,它允许您在视图之间共享相同的数据。

此外,ViewModel 类不应,或包含来自 Android 环境的最少类,也不应保留对视图类的任何引用,因为它可能比视图寿命更长。

在您的第二个示例中,您可能使用 Activity/Fragment 获得相同的 ViewModel

public void setViewModel(GalleryItemViewModel viewModel){
            this.viewModel = viewModel;
            binding.setViewModel(viewModel);
}
Run Code Online (Sandbox Code Playgroud)

您可以共享布局文件以及如何使用 ViewModel 类实现它吗?

已接受答案中的示例链接不是 MVVM 和数据绑定的正确示例。

链接中的 ViewModel 类设置为您的第二个示例:

public class CommentHeaderViewModel extends BaseObservable {

    private Context context;
    private Post post;

    public CommentHeaderViewModel(Context context, Post post) {
        this.context = context;
        this.post = post;
    }

    public String getCommentText() {
        return Html.fromHtml(post.text.trim()).toString();
    }

    public String getCommentAuthor() {
        return context.getResources().getString(R.string.text_comment_author, post.by);
    }

    public String getCommentDate() {
        return new PrettyTime().format(new Date(post.time * 1000));
    }

}
Run Code Online (Sandbox Code Playgroud)

这是一个数据类,而不是作为架构组件页面状态的 ViewModel 类,它还导入了不利于单元测试的视图类。

这是数据绑定 + RecyclerView 教程,正确的命名不应该是 ..ViewModel 这个类。查看本教程了解数据类并将其与 RecyclerView 绑定。

  • ViewModel 类不应具有上下文引用。 (4认同)
  • 我写的不应该,请仔细阅读。_另外,ViewModel 类不应该,或者包含来自 Android 环境的最小类,并且不应该保留对视图类的任何引用,因为它可能比视图更长寿。_ 该片段显示了 ViewModel 以前是如何使用的,现在不应该使用,它是数据类,当前未使用 ViewModel 的架构类。 (2认同)