From afc0d5b7bcce42cd3e7216624684d734b36451e5 Mon Sep 17 00:00:00 2001 From: yorha-0x <78670272+yorha-0x@users.noreply.github.com> Date: Thu, 11 Mar 2021 13:57:19 -0600 Subject: [PATCH] Update recyclerviews with diffutil (#711) Remove modified imports Co-authored-by: m2049r --- .../com/m2049r/xmrwallet/LoginFragment.java | 1 - .../com/m2049r/xmrwallet/NodeFragment.java | 4 +- .../com/m2049r/xmrwallet/WalletFragment.java | 3 - .../m2049r/xmrwallet/layout/DiffCallback.java | 29 ++++++++++ .../xmrwallet/layout/NodeInfoAdapter.java | 56 +++++++++++++------ .../layout/TransactionInfoAdapter.java | 49 ++++++++++++---- .../xmrwallet/layout/WalletInfoAdapter.java | 46 +++++++++++---- 7 files changed, 142 insertions(+), 46 deletions(-) create mode 100644 app/src/main/java/com/m2049r/xmrwallet/layout/DiffCallback.java diff --git a/app/src/main/java/com/m2049r/xmrwallet/LoginFragment.java b/app/src/main/java/com/m2049r/xmrwallet/LoginFragment.java index 183f1cb..c286d6e 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/LoginFragment.java +++ b/app/src/main/java/com/m2049r/xmrwallet/LoginFragment.java @@ -258,7 +258,6 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter walletList.addAll(walletInfos); filterList(); adapter.setInfos(displayedList); - adapter.notifyDataSetChanged(); // deal with Gunther & FAB animation if (displayedList.isEmpty()) { diff --git a/app/src/main/java/com/m2049r/xmrwallet/NodeFragment.java b/app/src/main/java/com/m2049r/xmrwallet/NodeFragment.java index f5eda55..6e652bf 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/NodeFragment.java +++ b/app/src/main/java/com/m2049r/xmrwallet/NodeFragment.java @@ -524,7 +524,7 @@ public class NodeFragment extends Fragment .setNegativeButton(getString(R.string.label_cancel), (dialog, id) -> { closeDialog(); - nodesAdapter.dataSetChanged(); // to refresh test results + nodesAdapter.setNodes(); // to refresh test results }); editDialog = alertDialogBuilder.create(); @@ -588,7 +588,7 @@ public class NodeFragment extends Fragment if (nodeBackup == null) { nodesAdapter.addNode(nodeInfo); } else { - nodesAdapter.dataSetChanged(); + nodesAdapter.setNodes(); } } } diff --git a/app/src/main/java/com/m2049r/xmrwallet/WalletFragment.java b/app/src/main/java/com/m2049r/xmrwallet/WalletFragment.java index 1a1ac10..0669e0a 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/WalletFragment.java +++ b/app/src/main/java/com/m2049r/xmrwallet/WalletFragment.java @@ -154,7 +154,6 @@ public class WalletFragment extends Fragment dismissedTransactions.add(adapter.getItem(position).hash); adapter.removeItem(position); } - adapter.notifyDataSetChanged(); } @Override @@ -163,7 +162,6 @@ public class WalletFragment extends Fragment dismissedTransactions.add(adapter.getItem(position).hash); adapter.removeItem(position); } - adapter.notifyDataSetChanged(); } }); @@ -352,7 +350,6 @@ public class WalletFragment extends Fragment list.add(info); } adapter.setInfos(list); - adapter.notifyDataSetChanged(); } updateStatus(wallet); } diff --git a/app/src/main/java/com/m2049r/xmrwallet/layout/DiffCallback.java b/app/src/main/java/com/m2049r/xmrwallet/layout/DiffCallback.java new file mode 100644 index 0000000..0cb84ae --- /dev/null +++ b/app/src/main/java/com/m2049r/xmrwallet/layout/DiffCallback.java @@ -0,0 +1,29 @@ +package com.m2049r.xmrwallet.layout; + +import androidx.recyclerview.widget.DiffUtil; + +import java.util.List; + +public abstract class DiffCallback extends DiffUtil.Callback { + + protected final List mOldList; + protected final List mNewList; + + public DiffCallback(List oldList, List newList) { + this.mOldList = oldList; + this.mNewList = newList; + } + + @Override + public int getOldListSize() { + return mOldList.size(); + } + + @Override + public int getNewListSize() { + return mNewList.size(); + } + public abstract boolean areItemsTheSame(int oldItemPosition, int newItemPosition); + + public abstract boolean areContentsTheSame(int oldItemPosition, int newItemPosition); +} \ No newline at end of file diff --git a/app/src/main/java/com/m2049r/xmrwallet/layout/NodeInfoAdapter.java b/app/src/main/java/com/m2049r/xmrwallet/layout/NodeInfoAdapter.java index c3eb244..31e3f60 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/layout/NodeInfoAdapter.java +++ b/app/src/main/java/com/m2049r/xmrwallet/layout/NodeInfoAdapter.java @@ -25,6 +25,7 @@ import android.widget.ImageView; import android.widget.TextView; import androidx.annotation.NonNull; +import androidx.recyclerview.widget.DiffUtil; import androidx.recyclerview.widget.RecyclerView; import com.m2049r.xmrwallet.R; @@ -63,6 +64,26 @@ public class NodeInfoAdapter extends RecyclerView.Adapter { + + public NodeDiff(List oldList, List newList) { + super(oldList, newList); + } + + @Override + public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) { + return mOldList.get(oldItemPosition).equals( + mNewList.get(newItemPosition) + ); + } + + @Override + public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) { + return mOldList.get(oldItemPosition).toNodeString().equals(mNewList.get(newItemPosition).toNodeString()) + && mOldList.get(oldItemPosition).isSelected() == mNewList.get(newItemPosition).isSelected() ; + } + } + @Override public @NonNull ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { @@ -82,25 +103,28 @@ public class NodeInfoAdapter extends RecyclerView.Adapter newItems = new ArrayList<>(nodeItems); if (!nodeItems.contains(node)) - nodeItems.add(node); - dataSetChanged(); // in case the nodeinfo has changed + newItems.add(node); + setNodes(newItems); // in case the nodeinfo has changed } - public void dataSetChanged() { - Collections.sort(nodeItems, NodeInfo.BestNodeComparator); - notifyDataSetChanged(); - } - - public void setNodes(Collection data) { - nodeItems.clear(); - if (data != null) { - for (NodeInfo node : data) { - if (!nodeItems.contains(node)) - nodeItems.add(node); - } + public void setNodes(Collection newItemsCollection) { + List newItems; + if(newItemsCollection !=null) { + newItems = new ArrayList<>(newItemsCollection); + Collections.sort(newItems, NodeInfo.BestNodeComparator); + } else { + newItems = new ArrayList<>(); } - dataSetChanged(); + final NodeInfoAdapter.NodeDiff diffCallback = new NodeInfoAdapter.NodeDiff(nodeItems,newItems); + final DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(diffCallback); + nodeItems.clear(); + nodeItems.addAll(newItems); + diffResult.dispatchUpdatesTo(this); + } + public void setNodes() { + setNodes(nodeItems); } private boolean itemsClickable = true; @@ -130,7 +154,7 @@ public class NodeInfoAdapter extends RecyclerView.Adapter { + + public TransactionInfoDiff(List oldList, List newList) { + super(oldList, newList); + } + + @Override + public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) { + return mOldList.get(oldItemPosition).hash.equals( + mNewList.get(newItemPosition).hash + ); + } + + @Override + public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) { + return mOldList.get(oldItemPosition).isPending == mNewList.get(newItemPosition).isPending && + mOldList.get(oldItemPosition).isFailed == mNewList.get(newItemPosition).isFailed ; + } + } + @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()) @@ -90,23 +112,26 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter data) { - // TODO do stuff with data so we can really recycle elements (i.e. add only new tx) - // as the TransactionInfo items are always recreated, we cannot recycle - infoItems.clear(); - if (data != null) { - Timber.d("setInfos %s", data.size()); - infoItems.addAll(data); - Collections.sort(infoItems); - } else { + public void setInfos(List newItems) { + if(newItems == null) { + newItems = new ArrayList<>(); Timber.d("setInfos null"); + } else { + Timber.d("setInfos %s", newItems.size()); } - notifyDataSetChanged(); + Collections.sort(newItems); + final DiffCallback diffCallback = new TransactionInfoAdapter.TransactionInfoDiff(infoItems,newItems); + final DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(diffCallback); + infoItems.clear(); + infoItems.addAll(newItems); + diffResult.dispatchUpdatesTo(this); } public void removeItem(int position) { - infoItems.remove(position); - notifyItemRemoved(position); + List newItems = new ArrayList<>(infoItems); + if (newItems.size()>position) + newItems.remove(position); + setInfos(newItems); // in case the nodeinfo has changed } public TransactionInfo getItem(int position) { diff --git a/app/src/main/java/com/m2049r/xmrwallet/layout/WalletInfoAdapter.java b/app/src/main/java/com/m2049r/xmrwallet/layout/WalletInfoAdapter.java index 77f0937..514b9a6 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/layout/WalletInfoAdapter.java +++ b/app/src/main/java/com/m2049r/xmrwallet/layout/WalletInfoAdapter.java @@ -17,8 +17,6 @@ package com.m2049r.xmrwallet.layout; import android.content.Context; -import androidx.appcompat.widget.PopupMenu; -import androidx.recyclerview.widget.RecyclerView; import android.view.LayoutInflater; import android.view.MenuItem; import android.view.View; @@ -26,6 +24,10 @@ import android.view.ViewGroup; import android.widget.ImageButton; import android.widget.TextView; +import androidx.appcompat.widget.PopupMenu; +import androidx.recyclerview.widget.DiffUtil; +import androidx.recyclerview.widget.RecyclerView; + import com.m2049r.xmrwallet.R; import com.m2049r.xmrwallet.model.WalletManager; @@ -62,6 +64,24 @@ public class WalletInfoAdapter extends RecyclerView.Adapter { + + public WalletInfoDiff(List oldList, List newList) { + super(oldList, newList); + } + + @Override + public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) { + return mOldList.get(oldItemPosition).name.equals( + mNewList.get(newItemPosition).name + ); + } + + @Override + public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) { + return mOldList.get(oldItemPosition).compareTo(mNewList.get(newItemPosition)) == 0; + } + } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { @@ -84,20 +104,22 @@ public class WalletInfoAdapter extends RecyclerView.Adapter data) { - // TODO do stuff with data so we can really recycle elements (i.e. add only new tx) - // as the WalletInfo items are always recreated, we cannot recycle - infoItems.clear(); - if (data != null) { - Timber.d("setInfos %s", data.size()); - infoItems.addAll(data); - Collections.sort(infoItems); - } else { + public void setInfos(List newItems) { + if(newItems == null) { + newItems = new ArrayList<>(); Timber.d("setInfos null"); + } else { + Timber.d("setInfos %s", newItems.size()); } - notifyDataSetChanged(); + Collections.sort(newItems); + final DiffCallback diffCallback = new WalletInfoAdapter.WalletInfoDiff(infoItems,newItems); + final DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(diffCallback); + infoItems.clear(); + infoItems.addAll(newItems); + diffResult.dispatchUpdatesTo(this); } + class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { final TextView tvName; final TextView tvAddress;