行为解释:使用 LiveData 通过 DiffUtil 更新适配器
behavior explanation: Using LiveData to update adapter with DiffUtil
我正在使用 LiveData
更新我的 recyclerview,如下所示:
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();
}
});
我正在使用 FloatActionButton
来更改 MutableLiveData
的值,如下所示:
FloatingActionButton fab = view.findViewById(R.id.cart_fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
viewModel.setPurchasePrice(0, 101.2);
}
});
所有数据都已更改,并且按预期调用了 onChanged
,但它仅在我启用 adapter.notifyDataSetChanged();
时更新我的回收视图
如果我在 FAB 中创建一个新的 ProductsObject
并 提交 一个新列表,recyclerview 会在不调用 adapter.notifyDataSetChanged();
的情况下更新,如下所示:
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);
}
});
如果有人能解释原因,我将不胜感激。
这是我的适配器:
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);
}
}
}
这是我的 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);
}
}
}
AsyncListDiffer
只保存列表的引用。这意味着如果您提交修改后的列表而不是提交新列表,AsncListDiffer
将无法检测到任何差异,因为之前的列表和新列表都引用具有相同项目的相同列表。
要解决此问题,您需要创建一个新列表和新项目。更改 MyViewModel#setPurchasePrice
如下:
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);
}
}
我正在使用 LiveData
更新我的 recyclerview,如下所示:
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();
}
});
我正在使用 FloatActionButton
来更改 MutableLiveData
的值,如下所示:
FloatingActionButton fab = view.findViewById(R.id.cart_fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
viewModel.setPurchasePrice(0, 101.2);
}
});
所有数据都已更改,并且按预期调用了 onChanged
,但它仅在我启用 adapter.notifyDataSetChanged();
如果我在 FAB 中创建一个新的 ProductsObject
并 提交 一个新列表,recyclerview 会在不调用 adapter.notifyDataSetChanged();
的情况下更新,如下所示:
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);
}
});
如果有人能解释原因,我将不胜感激。
这是我的适配器:
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);
}
}
}
这是我的 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);
}
}
}
AsyncListDiffer
只保存列表的引用。这意味着如果您提交修改后的列表而不是提交新列表,AsncListDiffer
将无法检测到任何差异,因为之前的列表和新列表都引用具有相同项目的相同列表。
要解决此问题,您需要创建一个新列表和新项目。更改 MyViewModel#setPurchasePrice
如下:
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);
}
}