Update recyclerviews with diffutil (#711)

Remove modified imports

Co-authored-by: m2049r <m2049r@monerujo.io>
This commit is contained in:
yorha-0x 2021-03-11 13:57:19 -06:00 committed by GitHub
parent 02e92db59a
commit afc0d5b7bc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 142 additions and 46 deletions

View File

@ -258,7 +258,6 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
walletList.addAll(walletInfos); walletList.addAll(walletInfos);
filterList(); filterList();
adapter.setInfos(displayedList); adapter.setInfos(displayedList);
adapter.notifyDataSetChanged();
// deal with Gunther & FAB animation // deal with Gunther & FAB animation
if (displayedList.isEmpty()) { if (displayedList.isEmpty()) {

View File

@ -524,7 +524,7 @@ public class NodeFragment extends Fragment
.setNegativeButton(getString(R.string.label_cancel), .setNegativeButton(getString(R.string.label_cancel),
(dialog, id) -> { (dialog, id) -> {
closeDialog(); closeDialog();
nodesAdapter.dataSetChanged(); // to refresh test results nodesAdapter.setNodes(); // to refresh test results
}); });
editDialog = alertDialogBuilder.create(); editDialog = alertDialogBuilder.create();
@ -588,7 +588,7 @@ public class NodeFragment extends Fragment
if (nodeBackup == null) { if (nodeBackup == null) {
nodesAdapter.addNode(nodeInfo); nodesAdapter.addNode(nodeInfo);
} else { } else {
nodesAdapter.dataSetChanged(); nodesAdapter.setNodes();
} }
} }
} }

View File

@ -154,7 +154,6 @@ public class WalletFragment extends Fragment
dismissedTransactions.add(adapter.getItem(position).hash); dismissedTransactions.add(adapter.getItem(position).hash);
adapter.removeItem(position); adapter.removeItem(position);
} }
adapter.notifyDataSetChanged();
} }
@Override @Override
@ -163,7 +162,6 @@ public class WalletFragment extends Fragment
dismissedTransactions.add(adapter.getItem(position).hash); dismissedTransactions.add(adapter.getItem(position).hash);
adapter.removeItem(position); adapter.removeItem(position);
} }
adapter.notifyDataSetChanged();
} }
}); });
@ -352,7 +350,6 @@ public class WalletFragment extends Fragment
list.add(info); list.add(info);
} }
adapter.setInfos(list); adapter.setInfos(list);
adapter.notifyDataSetChanged();
} }
updateStatus(wallet); updateStatus(wallet);
} }

View File

@ -0,0 +1,29 @@
package com.m2049r.xmrwallet.layout;
import androidx.recyclerview.widget.DiffUtil;
import java.util.List;
public abstract class DiffCallback<T> extends DiffUtil.Callback {
protected final List<T> mOldList;
protected final List<T> mNewList;
public DiffCallback(List<T> oldList, List<T> 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);
}

View File

@ -25,6 +25,7 @@ import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.recyclerview.widget.DiffUtil;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import com.m2049r.xmrwallet.R; import com.m2049r.xmrwallet.R;
@ -63,6 +64,26 @@ public class NodeInfoAdapter extends RecyclerView.Adapter<NodeInfoAdapter.ViewHo
TS_FORMATTER.setTimeZone(tz); TS_FORMATTER.setTimeZone(tz);
} }
private static class NodeDiff extends DiffCallback<NodeInfo> {
public NodeDiff(List<NodeInfo> oldList, List<NodeInfo> 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 @Override
public @NonNull public @NonNull
ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
@ -82,25 +103,28 @@ public class NodeInfoAdapter extends RecyclerView.Adapter<NodeInfoAdapter.ViewHo
} }
public void addNode(NodeInfo node) { public void addNode(NodeInfo node) {
List<NodeInfo> newItems = new ArrayList<>(nodeItems);
if (!nodeItems.contains(node)) if (!nodeItems.contains(node))
nodeItems.add(node); newItems.add(node);
dataSetChanged(); // in case the nodeinfo has changed setNodes(newItems); // in case the nodeinfo has changed
} }
public void dataSetChanged() { public void setNodes(Collection<NodeInfo> newItemsCollection) {
Collections.sort(nodeItems, NodeInfo.BestNodeComparator); List<NodeInfo> newItems;
notifyDataSetChanged(); if(newItemsCollection !=null) {
} newItems = new ArrayList<>(newItemsCollection);
Collections.sort(newItems, NodeInfo.BestNodeComparator);
public void setNodes(Collection<NodeInfo> data) { } else {
nodeItems.clear(); newItems = new ArrayList<>();
if (data != null) {
for (NodeInfo node : data) {
if (!nodeItems.contains(node))
nodeItems.add(node);
}
} }
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; private boolean itemsClickable = true;
@ -130,7 +154,7 @@ public class NodeInfoAdapter extends RecyclerView.Adapter<NodeInfoAdapter.ViewHo
showStar(); showStar();
if (!nodeItem.isFavourite()) { if (!nodeItem.isFavourite()) {
nodeItem.setSelected(false); nodeItem.setSelected(false);
notifyDataSetChanged(); setNodes(nodeItems);
} }
}); });
itemView.setOnClickListener(this); itemView.setOnClickListener(this);

View File

@ -24,6 +24,7 @@ import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.DiffUtil;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import com.m2049r.xmrwallet.R; import com.m2049r.xmrwallet.R;
@ -73,6 +74,27 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo
DATETIME_FORMATTER.setTimeZone(tz); DATETIME_FORMATTER.setTimeZone(tz);
} }
private static class TransactionInfoDiff extends DiffCallback<TransactionInfo> {
public TransactionInfoDiff(List<TransactionInfo> oldList, List<TransactionInfo> 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 @Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()) View view = LayoutInflater.from(parent.getContext())
@ -90,23 +112,26 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo
return infoItems.size(); return infoItems.size();
} }
public void setInfos(List<TransactionInfo> data) { public void setInfos(List<TransactionInfo> newItems) {
// TODO do stuff with data so we can really recycle elements (i.e. add only new tx) if(newItems == null) {
// as the TransactionInfo items are always recreated, we cannot recycle newItems = new ArrayList<>();
infoItems.clear();
if (data != null) {
Timber.d("setInfos %s", data.size());
infoItems.addAll(data);
Collections.sort(infoItems);
} else {
Timber.d("setInfos null"); Timber.d("setInfos null");
} else {
Timber.d("setInfos %s", newItems.size());
} }
notifyDataSetChanged(); Collections.sort(newItems);
final DiffCallback<TransactionInfo> 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) { public void removeItem(int position) {
infoItems.remove(position); List<TransactionInfo> newItems = new ArrayList<>(infoItems);
notifyItemRemoved(position); if (newItems.size()>position)
newItems.remove(position);
setInfos(newItems); // in case the nodeinfo has changed
} }
public TransactionInfo getItem(int position) { public TransactionInfo getItem(int position) {

View File

@ -17,8 +17,6 @@
package com.m2049r.xmrwallet.layout; package com.m2049r.xmrwallet.layout;
import android.content.Context; import android.content.Context;
import androidx.appcompat.widget.PopupMenu;
import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
@ -26,6 +24,10 @@ import android.view.ViewGroup;
import android.widget.ImageButton; import android.widget.ImageButton;
import android.widget.TextView; 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.R;
import com.m2049r.xmrwallet.model.WalletManager; import com.m2049r.xmrwallet.model.WalletManager;
@ -62,6 +64,24 @@ public class WalletInfoAdapter extends RecyclerView.Adapter<WalletInfoAdapter.Vi
TimeZone tz = cal.getTimeZone(); //get the local time zone. TimeZone tz = cal.getTimeZone(); //get the local time zone.
DATETIME_FORMATTER.setTimeZone(tz); DATETIME_FORMATTER.setTimeZone(tz);
} }
private static class WalletInfoDiff extends DiffCallback<WalletManager.WalletInfo> {
public WalletInfoDiff(List<WalletManager.WalletInfo> oldList, List<WalletManager.WalletInfo> 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 @Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
@ -84,20 +104,22 @@ public class WalletInfoAdapter extends RecyclerView.Adapter<WalletInfoAdapter.Vi
return infoItems.get(position); return infoItems.get(position);
} }
public void setInfos(List<WalletManager.WalletInfo> data) { public void setInfos(List<WalletManager.WalletInfo> newItems) {
// TODO do stuff with data so we can really recycle elements (i.e. add only new tx) if(newItems == null) {
// as the WalletInfo items are always recreated, we cannot recycle newItems = new ArrayList<>();
infoItems.clear();
if (data != null) {
Timber.d("setInfos %s", data.size());
infoItems.addAll(data);
Collections.sort(infoItems);
} else {
Timber.d("setInfos null"); Timber.d("setInfos null");
} else {
Timber.d("setInfos %s", newItems.size());
} }
notifyDataSetChanged(); Collections.sort(newItems);
final DiffCallback<WalletManager.WalletInfo> 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 { class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
final TextView tvName; final TextView tvName;
final TextView tvAddress; final TextView tvAddress;