我正在尝试使用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();
}
}
工作正常,但它非常基本。如何更新它,以便每个项目都有自己的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();
}
}
它有效,但这是正确的方法吗?
答案 0 :(得分:7)
有趣,但回答 - 这是正确的方法,应该被接受:)
您可以清除一些代码并从GalleryItemViewModel
中删除PostViewHolder
,因为您正在创建硬引用而不使用它。
然后在onBindViewHolder()
中直接使用holder.binding.setViewModel(vm);
这是一个带有MVVM代码示例的link,可以帮助您。
答案 1 :(得分:2)
首先,正确地实现ViewModel的方法应该是扩展android.arch.lifecycle.ViewModel
。扩展BaseObservable
的示例使ViewModel类成为数据类,但应将其作为表示形式类,因为它取代了MVP模式的表示者。
另一件事是ViewModelProviders.of(context).get(Class.class)
为每个调用返回相同的ViewModel,它使您可以在视图之间共享相同的数据。
此外,ViewModel类不应包含或包含Android环境中的最少类,并且不应保留对视图类的任何引用,因为它可能会超出视图的寿命。
在第二个示例中,您可能使用
从Activity / Fragment获取相同的ViewModelpublic void setViewModel(GalleryItemViewModel viewModel){
this.viewModel = viewModel;
binding.setViewModel(viewModel);
}
您可以共享布局文件以及如何使用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));
}
}
这是一个数据类,而不是architecture components page所述的ViewModel类,它还导入了对单元测试不利的视图类。
这是数据绑定+ RecyclerView教程,此类的正确命名不应为..ViewModel。 Check out this tutorial用于数据类,并将其与RecyclerView绑定。
答案 2 :(得分:0)
请确保在获取ViewModel时分配一个唯一的标识符,因为ViewModelProviders会在后台为您提供相同的实例
get(一些唯一ID ,GalleryItemViewModel.class);
所以请尝试在其中添加一个ID,如下所示:
GalleryItemViewModel vm = ViewModelProviders.of((FragmentActivity) holder.getContext()).get(**some unique id**, GalleryItemViewModel.class);
vm.setPost(list.get(position));
holder.setViewModel(vm);