databinding - Componentes de la arquitectura de Android: uso de ViewModel para elementos RecyclerView
recyclerview databinding kotlin (2)
En primer lugar, la implementación correcta de ViewModel debe ser extendiendo android.arch.lifecycle.ViewModel
. Los ejemplos que amplían BaseObservable
que hace que la clase ViewModel sea una clase de datos, deben ser una clase de presentación, ya que está reemplazando al presentador del patrón MVP.
Otra cosa es ViewModelProviders.of(context).get(Class.class)
devuelve el mismo ViewModel para cada llamada y le permite compartir los mismos datos entre las vistas.
Además, la clase ViewModel no debe, o debe contener clases mínimas del entorno de Android y no debe mantener ninguna referencia para ver las clases, ya que puede sobrevivir a las vistas.
En su segundo ejemplo, probablemente obtenga el mismo ViewModel de Activity / Fragment usando
public void setViewModel(GalleryItemViewModel viewModel){
this.viewModel = viewModel;
binding.setViewModel(viewModel);
}
¿Puede compartir el archivo de diseño y cómo implementarlo con la clase ViewModel?
El enlace para la muestra en la respuesta aceptada no es un ejemplo correcto para MVVM y enlace de datos.
La clase ViewModel del conjunto de enlaces como segundo ejemplo:
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));
}
}
Esta es una clase de datos, no una clase ViewModel como los estados de la página de componentes de la arquitectura , también importa clases de vista, lo que es malo para la prueba de unidades.
Es enlace de datos + tutorial RecyclerView, la denominación correcta no debe ser ..ViewModel para esta clase. Echa un vistazo a este tutorial para la clase de datos y vincúlalo con RecyclerView.
Estoy experimentando con los Componentes de Arquitectura, y quiero construir un ViewModel para cada elemento de un RecyclerView. No estoy seguro de si eso es formalmente correcto o debo seguir con la "forma antigua".
Tengo este adaptador:
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();
}
}
que funciona bien pero es muy básico. ¿Cómo lo actualizo para que cada elemento tenga asociado su propio ViewModel? ¿Es eso posible?
EDITAR: jugando con él, he intentado poner ViewModels de la siguiente manera:
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();
}
}
Funciona pero ¿es esa la forma correcta de hacerlo?
Es curioso, pero responda: esta es la forma correcta, debe aceptarse :) Puede realizar una limpieza del código y eliminar GalleryItemViewModel
de PostViewHolder
, porque está creando una referencia difícil y no la está utilizando. Luego, directamente en onBindViewHolder()
utilícelo como holder.binding.setViewModel(vm);
Este es un link con un ejemplo de código MVVM que puede ayudarlo.