在回收者视图的适配器内的单个项目视图中使用ViewModel方法是否很好?

时间:2019-07-01 20:35:58

标签: android mvvm viewmodel android-architecture-components

我通常在我的应用程序中使用MVVM架构组件,但我注意到我 可以使用回收者视图为适配器内的单个项目视图创建新的ViewModel

所以我的问题这是一个好习惯吗??为单个项目创建视图模型?我已经为片段创建了一个视图模型,但是为什么要为适配器和单个项目视图呢? 将创建2个视图模型!感谢您的帮助。

让我们看看:

AllShopsItem.java

用作项目的模型

public class AllShopsItem {

private String image;
private String name;
private float rate;
private String details;
private String miniCharge;
private String shipping;

public AllShopsItem(String image, String name, float rate, String details, String miniCharge, String shipping) {
    this.image = image;
    this.name = name;
    this.rate = rate;
    this.details = details;
    this.miniCharge = miniCharge;
    this.shipping = shipping;
}

public String getImage() {
    return image;
}

public void setImage(String image) {
    this.image = image;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public float getRate() {
    return rate;
}

public void setRate(float rate) {
    this.rate = rate;
}

public String getDetails() {
    return details;
}

public void setDetails(String details) {
    this.details = details;
}

public String getMiniCharge() {
    return miniCharge;
}

public void setMiniCharge(String miniCharge) {
    this.miniCharge = miniCharge;
}

public String getShipping() {
    return shipping;
}

public void setShipping(String shipping) {
    this.shipping = shipping;
}
}//end model class

SingleItemAllShopsViewModel.java

项目的视图模型

public class SingleItemAllShopsViewModel extends BaseViewModel {
private AllShopsItem allShopsItem;

public SingleItemAllShopsViewModel(AllShopsItem allShopsItem) {
    this.allShopsItem = allShopsItem;
}

public void setUp() {
    // perform set up tasks, such as adding listeners
}

public void disposeListeners() {
    // perform tear such as removing listeners
}

@Bindable
public AllShopsItem getAllShopsItem() {
    return allShopsItem;
}

@BindingAdapter({"imageUrl"})
public static void setImageUrl(ImageView view, String imagePath){
    Timber.d(imagePath);
    ConnectionHelper.loadImage(view,  imagePath);
}

}//end viewmodel

AllShopsViewHolder.java

适配器的观察架

public class AllShopsViewHolder extends RecyclerView.ViewHolder {
private SingleItemAllShopsBinding binding;

public AllShopsViewHolder(@NonNull View itemView) {
    super(itemView);
    bind();
}

public void bind() {
    if (binding == null) {
        binding = DataBindingUtil.bind(itemView);
    }
}

public void unbind() {
    if (binding != null) {
        binding.unbind(); // Don't forget to unbind
    }
}

public void setViewModel(SingleItemAllShopsViewModel viewModel) {
    if (binding != null) {
        binding.setViewModelBinding(viewModel);
    }
}

}//end view holder

AllShopsAdapter.java

适配器类

public class AllShopsAdapter extends RecyclerView.Adapter<AllShopsViewHolder> {
private ArrayList<AllShopsItem> dataList;

public void setNewDataList(ArrayList<AllShopsItem> dataList) {
    this.dataList = dataList;
    notifyDataSetChanged();
}

public void updateDataList(ArrayList<AllShopsItem> dataList) {
    this.dataList.clear();
    this.dataList.addAll(dataList);
    notifyDataSetChanged();
}

@Override
public void onViewAttachedToWindow(@NonNull AllShopsViewHolder holder) {
    super.onViewAttachedToWindow(holder);
    Timber.d("onViewAttachedToWindow");
    holder.bind();
}

@Override
public void onViewDetachedFromWindow(@NonNull AllShopsViewHolder holder) {
    super.onViewDetachedFromWindow(holder);
    Timber.d("onViewDetachedFromWindow");
    holder.unbind();
}

@NonNull
@Override
public AllShopsViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.single_item_all_shops,
            new FrameLayout(parent.getContext()), false);
    return new AllShopsViewHolder(itemView);
}

@Override
public void onBindViewHolder(@NonNull AllShopsViewHolder holder, int position) {
    SingleItemAllShopsViewModel allShopsViewModel = new SingleItemAllShopsViewModel(getCurrentItem(position));
    holder.setViewModel(allShopsViewModel);
}

public AllShopsItem getCurrentItem(int pos) {
    return dataList.get(pos);
}

@Override
public int getItemCount() {
    return dataList != null && !dataList.isEmpty() ? dataList.size() : 0;
}
}//end adapter

single_item_all_shops.xml

单项设计

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">

<data>
    <variable
        name="viewModelBinding"


type="grand.shopness.view.adapter.itemviewmodel.SingleItemAllShopsViewModel" />
</data>

<androidx.cardview.widget.CardView
    android:id="@+id/cv_root"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <RelativeLayout
        android:id="@+id/rl_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:paddingStart="@dimen/dp16w"
        android:paddingEnd="@dimen/dp16w"
        android:paddingTop="@dimen/dp8h"
        android:paddingBottom="@dimen/dp8h">

        <androidx.cardview.widget.CardView
            android:id="@+id/cv_image"
            android:layout_width="80dp"
            android:layout_height="80dp"
            app:cardElevation="8dp"
            android:layout_centerVertical="true"
            android:layout_alignParentStart="true">
        <ImageView
            android:id="@+id/imageView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            tools:src="@drawable/slider_img"
            android:scaleType="fitXY"
            tools:ignore="ContentDescription"
            app:imageUrl="@{viewModelBinding.allShopsItem.image}"/>
        </androidx.cardview.widget.CardView>


        <RelativeLayout
            android:id="@+id/rl_info"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_toEndOf="@id/cv_image"
            android:paddingStart="@dimen/dp4w"
            android:paddingEnd="@dimen/dp4w"
            android:layout_toStartOf="@id/rl_prices"
            android:layout_centerVertical="true">

            <TextView
                android:id="@+id/tv_name"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentTop="true"
                android:fontFamily="@font/raleway_medium"
                tools:text="Shop name"
                android:textColor="@android:color/black"
                android:textSize="14sp"
                android:textStyle="bold"
                android:text="@{viewModelBinding.allShopsItem.name}"/>

            <RatingBar
                android:id="@+id/ratingBar"
                style="@style/RatingBarStyle"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_below="@id/tv_name"
                android:indeterminate="false"
                android:numStars="5"
                android:layout_marginTop="@dimen/dp2h"
                android:layout_alignParentStart="true"
                tools:rating="5"
                android:rating="@{viewModelBinding.allShopsItem.rate}"/>

            <TextView
                android:id="@+id/tv_details"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:fontFamily="@font/raleway_medium"
                tools:text="detailssssssssssssssasdasdasdsadasdasdasdasdadasdasdasdasdasdasdasdasdsssss"
                android:textColor="@android:color/black"
                android:layout_alignParentStart="true"
                android:layout_below="@id/ratingBar"
                android:maxLines="2"
                android:ellipsize="end"
                android:text="@{viewModelBinding.allShopsItem.details}"/>

        </RelativeLayout>

        <RelativeLayout
            android:id="@+id/rl_prices"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentEnd="true"
            android:layout_centerVertical="true"
            android:layout_marginStart="@dimen/dp4w">

            <TextView
                android:id="@+id/tv_mini_charge_static"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:fontFamily="@font/raleway_medium"
                android:text="@string/mini_charge"
                android:textColor="@android:color/black"
                android:layout_centerHorizontal="true"
                android:layout_alignParentTop="true" />

            <TextView
                android:id="@+id/tv_mini_charge"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@{viewModelBinding.allShopsItem.miniCharge}"
                tools:text="150"
                android:textColor="@android:color/black"
                android:layout_centerHorizontal="true"
                android:layout_below="@id/tv_mini_charge_static"/>

            <TextView
                android:id="@+id/tv_shipping_static"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:fontFamily="@font/raleway_medium"
                android:text="@string/shipping"
                android:textColor="@android:color/black"
                android:layout_centerHorizontal="true"
                android:layout_below="@id/tv_mini_charge"/>

            <TextView
                android:id="@+id/tv_shipping"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                tools:text="10"
                android:text="@{viewModelBinding.allShopsItem.shipping}"
                android:textColor="@android:color/black"
                android:layout_centerHorizontal="true"
                android:layout_below="@id/tv_shipping_static"/>

        </RelativeLayout>
    </RelativeLayout>
</androidx.cardview.widget.CardView>
</layout>

其外观如下:

enter image description here

3 个答案:

答案 0 :(得分:1)

老实说,我不这么认为,这看起来很奇怪。是的,viewmodel旨在管理与UI相关的数据,并允许数据从配置更改中保留下来,但是这样做只是在没有任何正当理由的情况下为适配器增加了一些复杂性。您的viewmodel可以帮助您处理Activity / Fragment数据,包括recyclerview数据,就是这样,只需确保您的viewmodel正确保存了回收站的视图状态并保持适配器简单

答案 1 :(得分:1)

我认为这是一个坏主意。 原因是viewModel是为使用生命周期感知组件(例如Activity,Fragment)而创建的,而不是用于此类用途

官方文档指出

  

ViewModel是负责准备和管理的类   活动或片段的数据   official doc

答案 2 :(得分:1)

我认为Google的图片不清晰。 IMO,作为架构组件的ViewModel应该不同于表示该视图可观察数据的viewModel。

如果ViewModel只是一组可观察的数据,并且上面有可用的操作,则每个项目都有一个ViewModel是有意义的。 对我来说,作为体系结构组件,它似乎应该只伴随着Activity&Fragments。

IMO这是Google搞砸MVVM的地方,这使得编写“干净的代码”变得更加困难。