From 90dc3cf4f90ac3529b02c47a5c8fc61583550bea Mon Sep 17 00:00:00 2001 From: emanuele-f Date: Fri, 12 Feb 2021 23:53:40 +0100 Subject: [PATCH] Optimize RecyclerView operations This provides both better performance and nice animations --- .../remote_capture/CaptureService.java | 6 +++- .../remote_capture/ConnectionsFragment.java | 28 +++++++++++++-- .../remote_capture/ConnectionsListener.java | 3 ++ .../remote_capture/ConnectionsRegister.java | 36 +++++++++++++------ 4 files changed, 59 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/com/emanuelef/remote_capture/CaptureService.java b/app/src/main/java/com/emanuelef/remote_capture/CaptureService.java index c495b66b..0932db6c 100644 --- a/app/src/main/java/com/emanuelef/remote_capture/CaptureService.java +++ b/app/src/main/java/com/emanuelef/remote_capture/CaptureService.java @@ -354,7 +354,11 @@ public class CaptureService extends VpnService implements Runnable { } public void sendConnectionsDump(ConnDescriptor[] new_conns, ConnDescriptor[] conns_updates) { - conn_reg.updateConnections(new_conns, conns_updates); + if(new_conns.length > 0) + conn_reg.newConnections(new_conns); + + if(conns_updates.length > 0) + conn_reg.connectionsUpdates(conns_updates); } public void sendStatsDump(VPNStats stats) { diff --git a/app/src/main/java/com/emanuelef/remote_capture/ConnectionsFragment.java b/app/src/main/java/com/emanuelef/remote_capture/ConnectionsFragment.java index a8ffe664..320f0315 100644 --- a/app/src/main/java/com/emanuelef/remote_capture/ConnectionsFragment.java +++ b/app/src/main/java/com/emanuelef/remote_capture/ConnectionsFragment.java @@ -23,7 +23,6 @@ import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.os.Handler; -import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -114,8 +113,8 @@ public class ConnectionsFragment extends Fragment implements AppStateListener, C mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override - //public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { - public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int state) { + public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { + //public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int state) { int first_visibile_pos = layoutMan.findFirstCompletelyVisibleItemPosition(); int last_visible_pos = layoutMan.findLastCompletelyVisibleItemPosition(); int last_pos = mAdapter.getItemCount() - 1; @@ -191,6 +190,29 @@ public class ConnectionsFragment extends Fragment implements AppStateListener, C if(autoScroll) scrollToBottom(); }); + } + @Override + public void connectionsAdded(int start, int count) { + mHandler.post(() -> { + mAdapter.notifyItemRangeInserted(start, count); + + if(autoScroll) + scrollToBottom(); + }); + } + + @Override + public void connectionsRemoved(int start, int count) { + mHandler.post(() -> mAdapter.notifyItemRangeRemoved(start, count)); + } + + @Override + public void connectionsUpdated(int[] positions) { + mHandler.post(() -> { + for(int pos : positions) { + mAdapter.notifyItemChanged(pos); + } + }); } } diff --git a/app/src/main/java/com/emanuelef/remote_capture/ConnectionsListener.java b/app/src/main/java/com/emanuelef/remote_capture/ConnectionsListener.java index b52d5afc..aa7c0d88 100644 --- a/app/src/main/java/com/emanuelef/remote_capture/ConnectionsListener.java +++ b/app/src/main/java/com/emanuelef/remote_capture/ConnectionsListener.java @@ -21,4 +21,7 @@ package com.emanuelef.remote_capture; public interface ConnectionsListener { void connectionsChanges(); + void connectionsAdded(int start, int count); + void connectionsRemoved(int start, int count); + void connectionsUpdated(int[] positions); } diff --git a/app/src/main/java/com/emanuelef/remote_capture/ConnectionsRegister.java b/app/src/main/java/com/emanuelef/remote_capture/ConnectionsRegister.java index 75aaf05d..68da6c40 100644 --- a/app/src/main/java/com/emanuelef/remote_capture/ConnectionsRegister.java +++ b/app/src/main/java/com/emanuelef/remote_capture/ConnectionsRegister.java @@ -21,6 +21,8 @@ package com.emanuelef.remote_capture; import android.util.Log; +import java.util.Arrays; + public class ConnectionsRegister { private final ConnDescriptor[] items_ring; private int tail; @@ -47,9 +49,10 @@ public class ConnectionsRegister { return (tail - 1 + size) % size; } - private void newConnections(ConnDescriptor[] conns) { + public synchronized void newConnections(ConnDescriptor[] conns) { int in_items = Math.min((size - num_items), conns.length); int out_items = conns.length - in_items; + int insert_pos = num_items; for(ConnDescriptor conn: conns) { items_ring[tail] = conn; @@ -58,12 +61,22 @@ public class ConnectionsRegister { } untracked_items += out_items; + + if(mListener != null) { + if(out_items > 0) + mListener.connectionsRemoved(0, out_items); + + if(conns.length > 0) + mListener.connectionsAdded(insert_pos - out_items, conns.length); + } } - private void connectionsUpdates(ConnDescriptor[] conns) { + public synchronized void connectionsUpdates(ConnDescriptor[] conns) { int first_pos = firstPos(); int first_id = items_ring[first_pos].incr_id; int last_id = items_ring[lastPos()].incr_id; + int []changed_pos = new int[conns.length]; + int k = 0; Log.d(TAG, "connectionsUpdates: items=" + num_items + ", first_id=" + first_id + ", last_id=" + last_id); @@ -76,8 +89,19 @@ public class ConnectionsRegister { assert(items_ring[pos].incr_id == id); items_ring[pos] = conn; + + changed_pos[k++] = (pos + size - first_pos) % size; } } + + if(mListener != null) { + if(k != conns.length) { + // some untracked items where skipped, shrink the array + changed_pos = Arrays.copyOf(changed_pos, k); + } + + mListener.connectionsUpdated(changed_pos); + } } public synchronized void reset() { @@ -92,14 +116,6 @@ public class ConnectionsRegister { mListener.connectionsChanges(); } - public synchronized void updateConnections(ConnDescriptor[] new_conns, ConnDescriptor[] conns_updates) { - newConnections(new_conns); - connectionsUpdates(conns_updates); - - if(mListener != null) - mListener.connectionsChanges(); - } - public synchronized void setListener(ConnectionsListener listener) { mListener = listener; }