Optimize RecyclerView operations

This provides both better performance and nice animations
This commit is contained in:
emanuele-f 2021-02-12 23:53:40 +01:00
parent d08c3d3f64
commit 90dc3cf4f9
4 changed files with 59 additions and 14 deletions

View File

@ -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) {

View File

@ -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);
}
});
}
}

View File

@ -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);
}

View File

@ -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;
}