how to use Architecture Components ViewModel inside RecyclerView Adapter?

南笙酒味 提交于 2020-03-17 06:44:57

问题


I have multiple ViewHolders that work as separated views inside vertical RecyclerView. I'm practicing with the new Architecture Components ViewModel.

inside my ViewModel I have a couple of MutableLiveData lists that i want to observe. but how can i call the

ViewModelProviders.of((AppCompatActivity)getActivity()).get(FilterViewModel.class)

and

mFilterViewModel.getCountries().observe(this, new Observer<ArrayList<TagModel>>() {
            @Override
            public void onChanged(@Nullable ArrayList<TagModel> tagModels) {

            }
        });

without leaking the activity or save the activity inside the adapter.

my ViewModel

public class FilterViewModel extends ViewModel {

private final MutableLiveData<ArrayList<TagModel>> mCountries;
private final MutableLiveData<ArrayList<TagModel>> mSelectedCountryProvinceList;
private final MutableLiveData<ArrayList<TagModel>> mDistanceList;

public FilterViewModel(){

    mCountries = new MutableLiveData<>();
    mSelectedCountryProvinceList = new MutableLiveData<>();
    mDistanceList = new MutableLiveData<>();

    TagStore.getInstance().subscribe(new StoreObserver<TagSearchList>() {
        @Override
        public void update(TagSearchList object) {
            mCountries.setValue(object.getCountries());
        }

        @Override
        public void update(int id, TagSearchList object) {
            if (id == 5){
                TagStore.getInstance().unSubcribe(this);
                update(object);
            }
        }

        @Override
        public void error(String error) {

        }
    }).get(5,"parent");

    TagStore.getInstance().subscribe(new StoreObserver<TagSearchList>() {
        @Override
        public void update(TagSearchList object) {
            mSelectedCountryProvinceList.setValue(object.toList());
        }

        @Override
        public void update(int id, TagSearchList object) {
            if (id == 6){
                TagStore.getInstance().unSubcribe(this);
                update(object);
            }
        }

        @Override
        public void error(String error) {

        }
    }).get(6,"parent");

    TagStore.getInstance().subscribe(new StoreObserver<TagSearchList>() {
        @Override
        public void update(TagSearchList object) {
            mDistanceList.setValue(object.toList());
        }

        @Override
        public void update(int id, TagSearchList object) {
            if (id == 51){
                TagStore.getInstance().unSubcribe(this);
                update(object);
            }
        }

        @Override
        public void error(String error) {

        }
    }).get(51,"parent");

}

public void selectCountry(final TagModel country){
    TagStore.getInstance().subscribe(new StoreObserver<TagSearchList>() {
        @Override
        public void update(TagSearchList object) {
            mSelectedCountryProvinceList.setValue(object.toList());
        }

        @Override
        public void update(int id, TagSearchList object) {
            if (id == country.getId()){
                TagStore.getInstance().unSubcribe(this);
                update(object);
            }
        }

        @Override
        public void error(String error) {

        }
    }).get(country.getId(),"parent");
}

public LiveData<ArrayList<TagModel>> getCountries(){
    return mCountries;
}

public LiveData<ArrayList<TagModel>> getDistances(){
    return mDistanceList;
}

public LiveData<ArrayList<TagModel>> getProvinces(){
    return mSelectedCountryProvinceList;
}

}


回答1:


I am using Room Persistence library. Below is my code for recyclerview adapter using MVVM.

You can see CartViewModel and I have initialized it into the constructor. The constructor gets the context from the activity, and I have cast it into FragmentActivity.

private CartViewModel cartViewModel;

public CartListAdapter(Context context, List<CartModel> cartModels) {
        this.context = context;
        this.cartModels = cartModels;

        cartViewModel = ViewModelProviders.of((FragmentActivity) context).get(CartViewModel.class);
    }

Here is my full adapter class. I hope it will help.

public class CartListAdapter extends RecyclerView.Adapter<CartListAdapter.CartListViewHolder> {

private static final String TAG = "CartListAdapter";

private Context context;
private List<CartModel> cartModels;

private Double totalQuantity = 0.0;

private CartViewModel cartViewModel;

public CartListAdapter(Context context, List<CartModel> cartModels) {
    this.context = context;
    this.cartModels = cartModels;

    cartViewModel = ViewModelProviders.of((FragmentActivity) context).get(CartViewModel.class);
}

@NonNull
@Override
public CartListViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    return new CartListViewHolder(LayoutInflater.from(context).inflate(R.layout.list_all_cart_item,parent,false));
}

@Override
public void onBindViewHolder(@NonNull CartListViewHolder holder, int position) {

    CartModel cartModel = cartModels.get(position);

    Glide.with(context)
            .load(cartModel.getPPICLocate())
            .into(holder.cartItemImage);

    holder.tvCartProductName.setText(cartModel.getProductName());
    holder.tvCartProductCategory.setText(cartModel.getPCategorySubID());
    holder.tvCartProductPrice.setText(cartModel.getPPriceSales());
    holder.etCartProductQuantity.setText(cartModel.getPQuantity());

    holder.btnCartPQtIncrease.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {

            totalQuantity = Double.valueOf(holder.etCartProductQuantity.getText().toString());
            totalQuantity = totalQuantity+1;
            cartModel.setPQuantity(totalQuantity.toString());
            updateCart(cartModel);
        }
    });

    holder.btnCartPQtDecrease.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {

            totalQuantity = Double.valueOf(holder.etCartProductQuantity.getText().toString());
            totalQuantity = totalQuantity-1;
            cartModel.setPQuantity(totalQuantity.toString());
            updateCart(cartModel);


        }
    });
}



@Override
public int getItemCount() {
    return cartModels.size();
}

public class CartListViewHolder extends RecyclerView.ViewHolder{

    private ImageView cartItemImage;
    private TextView tvCartProductName,tvCartProductCategory,tvCartProductPrice,
            etCartProductQuantity,tvCartProductPrevPrice;
    private ImageButton btnCartPQtIncrease,btnCartPQtDecrease;

    public CartListViewHolder(@NonNull View itemView) {
        super(itemView);

        cartItemImage= itemView.findViewById(R.id.cartItemImage);
        tvCartProductName= itemView.findViewById(R.id.tvCartProductName);
        tvCartProductCategory= itemView.findViewById(R.id.tvCartProductCategory);
        tvCartProductPrice= itemView.findViewById(R.id.tvCartProductPrice);
        etCartProductQuantity= itemView.findViewById(R.id.etCartProductQuantity);
        tvCartProductPrevPrice= itemView.findViewById(R.id.tvCartProductPrevPrice);
        btnCartPQtIncrease= itemView.findViewById(R.id.btnCartPQtIncrease);
        btnCartPQtDecrease= itemView.findViewById(R.id.btnCartPQtDecrease);

    }
}

public void addItems(List<CartModel> cartModels) {
    this.cartModels = cartModels;
    notifyDataSetChanged();
}

private void updateCart(CartModel cartModel){
    String tqt = String.valueOf(cartModel.getPQuantity());
    Log.d(TAG, "updateQuantity: "+tqt);
    /*cartRepository.updateCartRepo(cartModel);*/
    cartViewModel.updateCartItemVM(cartModel);

}

}



回答2:


My solution to this issue is;

  • create a new variable(ViewModel) for the layout (fragment or activity layout)
  • in your activity or fragment get the instance of your viewModel with ViewModelProviders
  • hold the data which fills your recyclerView in MutableLiveData and observe it and fill the adapter of recyclerView with the value you observed

here you mut be careful not to create adapter instance in observe method. if you create it in observe method, it will make leaks



来源:https://stackoverflow.com/questions/44495323/how-to-use-architecture-components-viewmodel-inside-recyclerview-adapter

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!