Компоненты архитектуры Android: использование ViewModel для элементов RecyclerView
я экспериментирую с компонентами архитектуры, и я хочу построить ViewModel для каждого элемента RecyclerView. Я не уверен, что это формально правильно, или я должен придерживаться "старого способа".
у меня есть этот адаптер:
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? это вообще возможно?
EDIT: играя с ним, я попытался поместить в 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();
}
}
это работает, но это правильный способ сделать это?
2 ответов
смешно, но ответ-это правильный способ, должен быть принят :)
Вы можете сделать некоторую очистку кода и удалить GalleryItemViewModel
с PostViewHolder
, потому что вы создаете жесткую ссылку, а не использовать его.
Затем непосредственно в onBindViewHolder()
использовать его как holder.binding.setViewModel(vm);
это ссылке С примером кода MVVM, который может вам помочь.
прежде всего правильная реализация ViewModel должна быть путем расширения android.arch.lifecycle.ViewModel
. Примеры, которые расширяют BaseObservable
что делает класс ViewModel классом данных, но он должен быть классом представления, поскольку он заменяет презентатора шаблона MVP.
другое дело ViewModelProviders.of(context).get(Class.class)
возвращает один и тот же ViewModel для каждого вызова и позволяет обмениваться данными между представлениями.
кроме того, класс ViewModel не должен или содержать минимальные классы из среды Android и не следует сохранять ссылки на классы представления, так как они могут пережить представления.
во втором примере вы, вероятно, получаете тот же ViewModel из Activity/Fragment, используя
public 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));
}
}
этот является классом данных, а не классом ViewModel как страница компонентов архитектуры состояния, он также импортирует классы представления, что плохо для модульного тестирования.
это привязка данных + RecyclerView учебник, правильное именование не должно быть ..ViewModel для этого класса. проверьте этот учебник для класса данных и связывания его с RecyclerView.