1

I am updating my recyclerview by using LiveData as below:

viewModel = ViewModelProviders.of(getActivity()).get(MyViewModel.class);
viewModel.getPurchaseList().observe(getViewLifecycleOwner(), new Observer<List<ProductsObject>>() {
    @Override
    public void onChanged(@Nullable List<ProductsObject> productsObjects) {
        adapter.submitList(productsObjects);
        //adapter.notifyDataSetChanged();
    }
});

And I am using a FloatActionButton to change the value of my MutableLiveData as below:

FloatingActionButton fab = view.findViewById(R.id.cart_fab);
fab.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        viewModel.setPurchasePrice(0, 101.2);

    }
});

All the data gets changed and onChanged is called as expected, but it only updates my recyclerview when I enable the adapter.notifyDataSetChanged();

If I create a new ProductsObject inside the FAB and submit a new list, the recyclerview gets updated without calling adapter.notifyDataSetChanged(); as below:

FloatingActionButton fab = view.findViewById(R.id.cart_fab);
fab.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        //viewModel.setPurchaseAmount(0, 101.2);
        ProductsObject prod = new ProductsObject("6666", 5, 152.2, "new product");
        List<ProductsObject> prodList = new ArrayList<>();
        prodList.add(prod);
        adapter.submitList(prodList);
    }
});

I appreciate if anyone could explain why.

Here is my adapter:

public class CartFragAdapter extends RecyclerView.Adapter<CartFragAdapter.CartFragViewHolder> {

    private static final String TAG = "debinf PurchaseAdap";

    private static final DiffUtil.ItemCallback<ProductsObject> DIFF_CALLBACK = new DiffUtil.ItemCallback<ProductsObject>() {
        @Override
        public boolean areItemsTheSame(@NonNull ProductsObject oldProduct, @NonNull ProductsObject newProduct) {
            Log.i(TAG, "areItemsTheSame: old is "+oldProduct.getCode()+" ; new is "+newProduct.getCode());
            return oldProduct.getCode().equals(newProduct.getCode());
        }

        @Override
        public boolean areContentsTheSame(@NonNull ProductsObject oldProduct, @NonNull ProductsObject newProduct) {
            Log.i(TAG, "areContentsTheSame: old is "+oldProduct.getPrice()+" ; new is "+newProduct.getPrice());
            return oldProduct.getPrice() == newProduct.getPrice();
        }
    };

    private AsyncListDiffer<ProductsObject> differ = new AsyncListDiffer<ProductsObject>(this, DIFF_CALLBACK);

    @NonNull
    @Override
    public CartFragViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_purchase, parent, false);
        return new CartFragViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull CartFragViewHolder holder, int position) {
        final ProductsObject purchaseList = differ.getCurrentList().get(position);

        holder.mCode.setText(purchaseList.getCode());
        holder.mPrice.setText(String.valueOf(purchaseList.getPrice()));
        holder.mDescription.setText(purchaseList.getDescription());


    }

    @Override
    public int getItemCount() {
        Log.i(TAG, "getItemCount");
        return differ.getCurrentList().size();
    }

    public void submitList(List<ProductsObject> products){
        Log.i(TAG, "submitList: products.size is "+products.size());
        differ.submitList(products);
    }

    public class CartFragViewHolder extends RecyclerView.ViewHolder {

        public TextView mCode, mPrice, mDescription;

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

            mCode = (TextView) itemView.findViewById(R.id.item_productCode);
            mPrice = (TextView) itemView.findViewById(R.id.item_productPrice);
            mDescription = (TextView) itemView.findViewById(R.id.item_productDescription);
        }
    }
}

And here is my ViewModel:

public class MyViewModel extends ViewModel {

    MutableLiveData<List<ProductsObject>> purchaseList = new MutableLiveData<>();

    public LiveData<List<ProductsObject>> getPurchaseList() {
        return purchaseList;
    }

    public void setPurchasePrice(int position, double price) {
        List<ProductsObject> itemList = purchaseList.getValue();
        if (itemList != null && itemList.get(position) != null) {
            Log.i("debinf ViewModel", "setPurchaseAmount: "+itemList.get(position).getPrice());
            itemList.get(position).setPrice(price);
            purchaseList.postValue(itemList);
        }

    }

}
4

1 回答 1

3

AsyncListDiffer saves only the reference of the list. This means that if you submit a modified list instead of submitting a new list, AsncListDiffer won't be able to detect any difference because both the previous list and the new list are referencing the same list with the same items.

To fix this you need to create a new list and new item. Change MyViewModel#setPurchasePrice as below:

    public void setPurchasePrice(int position, double price) {
        List<ProductsObject> itemList = purchaseList.getValue();
        if (itemList != null && itemList.get(position) != null) {

            List<ProductsObject> newList = new ArrayList<>();

            for (int i = 0; i < itemList.size(); i++) {
                ProductsObject prevProd = itemList.get(i);

                if (i != position) {
                    newList.add(prevProd);
                } else {
                    ProductsObject newProd = new ProductsObject(..., price, ...);
                    newList.add(newProd);
                }
            }
            purchaseList.postValue(newList);
        }

    }
于 2019-10-07T21:19:30.150 回答