'How to update list in RecyclerView with DiffUtils?
How do you use DiffCallback to load a newList in RecyclerView when DiffUtil ItemCallback is being used.
I would like to give the user the option to return different size lists from the database when the user selects a different size I want the RecyclerView to update.
RecyclerViewAdatper
RecyclerViewAdapter extends ListAdapter<WordEntity, RecyclerViewAdapter.ViewHolder> {
private RecyclerViewAdapter() {
super(DIFF_CALLBACK);
}
private static final DiffUtil.ItemCallback<WordEntity> DIFF_CALLBACK = new DiffUtil.ItemCallback<WordEntiti>() {
@Override
public boolean areItemsTheSame...
@Override
public boolean areContentsTheSame...
};
@Override
public viewHolder onCreateViewHolder...
@Override
public void onVindViewHolder ...
class ViewHolder extends RecyclerView.ViewHolder ...
public void updateWordList(List<WordEntity> words) {
final WordDiffCallBack diffCallBack = new WordDiffCallBack(list???, words);
final DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(diffCallBack);
this.list???.clear();
this.addAll(words);
diffResult.dispatcheUpdatesTo(this);
}
WordsDiffCallBack
private final List<WordEntity> mOldList;
private final List<WordEntity> mNewList;
public WordsDiffCallBack(List<WordEntity> oldList, List<WordEntity> newList) {
this.mOldList = oldList;
this.mNewList = newList;
}
@Override
public int getOldListSize() {
return mOldList.size();
}
@Override
public int getNewListSize() {
return mNewList.size();
}
@Override
public boolean areItemsTheSame(int OldItemPostion, int newItemPosition) ...
@Override boolean areContentsTheSame(int oldItemPosition, int newItemPosition)...
@Override getChangePayload(int oldItemPosition, int newItemPosition) ...
}
I want the RecycelView to update automatically when the size of the list gets changed by the user. How do I call the old list from the ListAdapter and will that even update the RecyclerView
Solution 1:[1]
You can create a template just like shown in this video in youTube:
https://www.youtube.com/watch?v=y31fzLe2Ajw
Here is an example of 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);
}
}
}
In MainActivity you call adapter like this:
CartFragAdapter adapter = new CartFragAdapter();
adapter.submitList(inputData);
I hope it helps!
Solution 2:[2]
observe this code
here's my diffutil callback
public class MyDiffUtilCallback extends DiffUtil.Callback {
List<String> oldlist;
List<String > newlist;
public MyDiffUtilCallback(List<String> oldlist, List<String> newlist) {
this.oldlist = oldlist;
this.newlist = newlist;
}
@Override
public int getOldListSize() {
return oldlist.size();
}
@Override
public int getNewListSize() {
return newlist.size();
}
@Override
public boolean areItemsTheSame(int olditempostion, int newitemPostion) {
return olditempostion==newitemPostion;
}
@Override
public boolean areContentsTheSame(int olditempostion, int newitemPostion) {
return olditempostion==newitemPostion;
}
@Nullable
@Override
public Object getChangePayload(int oldItemPosition, int newItemPosition) {
return super.getChangePayload(oldItemPosition, newItemPosition);
}
}
here's the recyclerview adpater which uses diffutilcallback
public class recyclerviewAdapter extends RecyclerView.Adapter<recyclerviewAdapter.Viewholder> {
List<String> datasource;
public recyclerviewAdapter(List<String> datasource) {
this.datasource = datasource;
}
@Override
public Viewholder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
View itemView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.demorow,viewGroup,false);
return new Viewholder(itemView);
}
@Override
public void onBindViewHolder(@NonNull Viewholder viewholder, int i) {
viewholder.tv_demo_data_row.setText(datasource.get(i));
}
@Override
public int getItemCount() {
return datasource.size();
}
public static class Viewholder extends RecyclerView.ViewHolder {
TextView tv_demo_data_row;
public Viewholder(@NonNull View itemView) {
super(itemView);
tv_demo_data_row=itemView.findViewById(R.id.tv_demo_data_row);
}
}
//DIFF CALLBACK STATE
public void insertdata(List<String> insertList){
/**
* Insert list insert data to list
*/
MyDiffUtilCallback diffUtilCallback = new MyDiffUtilCallback(datasource,insertList);
DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(diffUtilCallback);
datasource.addAll(insertList);
diffResult.dispatchUpdatesTo(this);
}
public void updateList(List<String> newList){
/**
* update list clear old data and update new data
*/
MyDiffUtilCallback diffUtilCallback = new MyDiffUtilCallback(datasource,newList);
DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(diffUtilCallback);
datasource.clear();
datasource.addAll(newList);
diffResult.dispatchUpdatesTo(this);
}}
and here i can update list in activity on button clickevent
insert_data.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//inserting the data
List<String> insertlist = new ArrayList<>(); //asign old list
for(int i=0;i<2;i++){
insertlist.add(UUID.randomUUID().toString()); // insert new list
adapter.insertdata(insertlist);
faster_recyclerview.smoothScrollToPosition(adapter.getItemCount()-1); //auto scroll to last postion
}
}
});
replace List of string with your modelclass
Solution 3:[3]
And in addition to the above (using DiffUtils), if you use Clicks to change RecyclerView's content, make
ViewHolder implements View.OnClickListener
and use this to set OnClickListener in onBindViewHolder
.setOnClickListener(holder);
and get your current position by
this.getAdapterPosition()
private class HistoryRecyclerAdapter extends RecyclerView.Adapter<HistoryRecyclerAdapter.ViewHolder> {
private List<HistoryEntry> entries;
HistoryRecyclerAdapter(List<HistoryEntry> entries) {
this.entries = entries;
}
public void updateContainer(List<HistoryEntry> list){
DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new DiffUtil.Callback() {
@Override
public int getOldListSize() { return entries.size(); }
@Override
public int getNewListSize() { return list.size(); }
@Override
public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
return entries.get(oldItemPosition).getId()==list.get(newItemPosition).getId();
}
@Override
public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
HistoryEntry old = entries.get(oldItemPosition);
HistoryEntry neww = list.get(newItemPosition);
return old.getExpression().equals(neww.getExpression())
&& old.getResult().equals(neww.getResult());
}
}, false);//detectMoves=true ????? ???????? ??????? ???????? ???? ?????? ?????? ???? ??????????
entries = list;
diffResult.dispatchUpdatesTo(this);
}
class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
//some Views
final Button delBtn;
ViewHolder(View view){
super(view);
//some Views
delBtn = (Button) view.findViewById(R.id.delete_btn);
}
@Override
public void onClick(View v) {
switch (v.getId()){
//some cases
case R.id.delete_btn:
historyManager.delete(entries.get(this.getAdapterPosition()));
break;
}
}
}
@NonNull
@Override
public HistoryRecyclerAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.history_row, parent, false);
return new HistoryRecyclerAdapter.ViewHolder(view);
}
@Override
public void onBindViewHolder(HistoryRecyclerAdapter.ViewHolder holder, final int position) {
//some code
holder.delBtn.setOnClickListener(holder);
}
@Override
public int getItemCount() {
return entries.size();
}
}
Early I used final int position in onBindViewHolder and don't understand what's wrong...)))
Solution 4:[4]
Here is snapet of my project (How to view list of my providers):
public class ProviderAdapter extends ListAdapter<Provider, RecyclerView.ViewHolder> {
private final GeneralListener<Provider> listener;
public ProviderAdapter(GeneralListener<Provider> listener) {
super(DIFF_CALLBACK);
this.listener = listener;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new ViewHolder(ItemProviderBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false));
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
((ViewHolder) holder).bind(getItem(position));
}
class ViewHolder extends RecyclerView.ViewHolder {
ItemProviderBinding binding;
public ViewHolder(ItemProviderBinding binding) {
super(binding.getRoot());
this.binding = binding;
}
void bind(Provider data) {
binding.image.setImageURI(data.img_url);
binding.txtName.setText(data.name);
binding.txtMealTypes.setText(data.meal_types);
binding.txtAddress.setText(data.address);
binding.btnBack.setOnClickListener(view -> {
listener.onClick(Actions.VIEW, data);
});
}
}
private static final DiffUtil.ItemCallback<Provider> DIFF_CALLBACK = new DiffUtil.ItemCallback<Provider>() {
@Override
public boolean areItemsTheSame(@NonNull Provider oldItem, @NonNull Provider newItem) {
return oldItem.id == newItem.id;
}
@Override
public boolean areContentsTheSame(@NonNull Provider oldItem, @NonNull Provider newItem) {
return oldItem.name.equals(newItem.name)
&& oldItem.meal_types.equals(newItem.meal_types)
&& oldItem.address.equals(newItem.address);
}
};
}
To use it:
ProviderAdapter adapter = new ProviderAdapter(new GeneralListener<Provider>() {
@Override
public void onClick(Actions action, Provider provider) {
if (action == Actions.VIEW) {
// TODO: View provider details
}
}
});
recyclerView.setAdapter(adapter);
adapter.submitList(providerList);
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Aliton Oliveira |
Solution 2 | Black mamba |
Solution 3 | Ermac |
Solution 4 | Mohammed Alomair |