mirror of
https://github.com/oxen-io/session-android.git
synced 2025-07-02 20:58:29 +00:00
Throttle conversation list update frequency.
This helps fast phones process messages faster by reducing contention on the database while processing a large batch of messages.
This commit is contained in:
parent
75c8c59d78
commit
63d6ab6fa7
@ -14,6 +14,7 @@ import org.thoughtcrime.securesms.database.DatabaseFactory;
|
|||||||
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
||||||
import org.thoughtcrime.securesms.database.model.ThreadRecord;
|
import org.thoughtcrime.securesms.database.model.ThreadRecord;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
|
import org.thoughtcrime.securesms.util.ThrottledDebouncer;
|
||||||
import org.thoughtcrime.securesms.util.concurrent.SignalExecutors;
|
import org.thoughtcrime.securesms.util.concurrent.SignalExecutors;
|
||||||
import org.thoughtcrime.securesms.util.paging.Invalidator;
|
import org.thoughtcrime.securesms.util.paging.Invalidator;
|
||||||
import org.thoughtcrime.securesms.util.paging.SizeFixResult;
|
import org.thoughtcrime.securesms.util.paging.SizeFixResult;
|
||||||
@ -26,6 +27,8 @@ abstract class ConversationListDataSource extends PositionalDataSource<Conversat
|
|||||||
|
|
||||||
public static final Executor EXECUTOR = SignalExecutors.newFixedLifoThreadExecutor("signal-conversation-list", 1, 1);
|
public static final Executor EXECUTOR = SignalExecutors.newFixedLifoThreadExecutor("signal-conversation-list", 1, 1);
|
||||||
|
|
||||||
|
private static final ThrottledDebouncer THROTTLER = new ThrottledDebouncer(500);
|
||||||
|
|
||||||
private static final String TAG = Log.tag(ConversationListDataSource.class);
|
private static final String TAG = Log.tag(ConversationListDataSource.class);
|
||||||
|
|
||||||
protected final ThreadDatabase threadDatabase;
|
protected final ThreadDatabase threadDatabase;
|
||||||
@ -36,8 +39,10 @@ abstract class ConversationListDataSource extends PositionalDataSource<Conversat
|
|||||||
ContentObserver contentObserver = new ContentObserver(null) {
|
ContentObserver contentObserver = new ContentObserver(null) {
|
||||||
@Override
|
@Override
|
||||||
public void onChange(boolean selfChange) {
|
public void onChange(boolean selfChange) {
|
||||||
invalidate();
|
THROTTLER.publish(() -> {
|
||||||
context.getContentResolver().unregisterContentObserver(this);
|
invalidate();
|
||||||
|
context.getContentResolver().unregisterContentObserver(this);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -0,0 +1,69 @@
|
|||||||
|
package org.thoughtcrime.securesms.util;
|
||||||
|
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Message;
|
||||||
|
|
||||||
|
import androidx.annotation.MainThread;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mixes the behavior of {@link Throttler} and {@link Debouncer}.
|
||||||
|
*
|
||||||
|
* Like a throttler, it will limit the number of runnables to be executed to be at most once every
|
||||||
|
* specified interval, while allowing the first runnable to be run immediately.
|
||||||
|
*
|
||||||
|
* However, like a debouncer, instead of completely discarding runnables that are published in the
|
||||||
|
* throttling period, the most recent one will be saved and run at the end of the throttling period.
|
||||||
|
*
|
||||||
|
* Useful for publishing a set of identical or near-identical tasks that you want to be responsive
|
||||||
|
* and guaranteed, but limited in execution frequency.
|
||||||
|
*/
|
||||||
|
public class ThrottledDebouncer {
|
||||||
|
|
||||||
|
private static final int WHAT = 24601;
|
||||||
|
|
||||||
|
private final OverflowHandler handler;
|
||||||
|
private final long threshold;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param threshold Only one runnable will be executed via {@link #publish(Runnable)} every
|
||||||
|
* {@code threshold} milliseconds.
|
||||||
|
*/
|
||||||
|
@MainThread
|
||||||
|
public ThrottledDebouncer(long threshold) {
|
||||||
|
this.handler = new OverflowHandler();
|
||||||
|
this.threshold = threshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainThread
|
||||||
|
public void publish(Runnable runnable) {
|
||||||
|
if (handler.hasMessages(WHAT)) {
|
||||||
|
handler.setRunnable(runnable);
|
||||||
|
} else {
|
||||||
|
runnable.run();
|
||||||
|
handler.sendMessageDelayed(handler.obtainMessage(WHAT), threshold);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainThread
|
||||||
|
public void clear() {
|
||||||
|
handler.removeCallbacksAndMessages(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class OverflowHandler extends Handler {
|
||||||
|
|
||||||
|
private Runnable runnable;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleMessage(Message msg) {
|
||||||
|
if (msg.what == WHAT && runnable != null) {
|
||||||
|
runnable.run();
|
||||||
|
runnable = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRunnable(@NonNull Runnable runnable) {
|
||||||
|
this.runnable = runnable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user