From 0fd1e0bff9bf7b18f4a5719859c10e1a450c7ae3 Mon Sep 17 00:00:00 2001 From: casey langen Date: Sat, 18 Feb 2017 13:55:42 -0800 Subject: [PATCH] Added code to debounce filtering on the client-side so we don't send a bunch of extra requests to the backend when searching. --- .../musikcube/remote/AlbumBrowseActivity.java | 19 +++++++--- .../remote/CategoryBrowseActivity.java | 18 +++++++--- .../io/casey/musikcube/remote/Debouncer.java | 35 +++++++++++++++++++ .../casey/musikcube/remote/MainActivity.java | 15 +++++--- .../musikcube/remote/TrackListActivity.java | 28 ++++++++++----- .../remote/WebSocketActivityBase.java | 7 ++++ 6 files changed, 100 insertions(+), 22 deletions(-) create mode 100644 src/musikdroid/app/src/main/java/io/casey/musikcube/remote/Debouncer.java diff --git a/src/musikdroid/app/src/main/java/io/casey/musikcube/remote/AlbumBrowseActivity.java b/src/musikdroid/app/src/main/java/io/casey/musikcube/remote/AlbumBrowseActivity.java index 559ac7a05..49074cd14 100644 --- a/src/musikdroid/app/src/main/java/io/casey/musikcube/remote/AlbumBrowseActivity.java +++ b/src/musikdroid/app/src/main/java/io/casey/musikcube/remote/AlbumBrowseActivity.java @@ -61,7 +61,7 @@ public class AlbumBrowseActivity extends WebSocketActivityBase implements Filter private TransportFragment transport; private String categoryName; private long categoryId; - private String filter = ""; + private String lastFilter = ""; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { @@ -97,8 +97,8 @@ public class AlbumBrowseActivity extends WebSocketActivityBase implements Filter @Override public void setFilter(String filter) { - this.filter = filter; - requery(); + this.lastFilter = filter; + filterDebouncer.call(filter); } @Override @@ -122,17 +122,28 @@ public class AlbumBrowseActivity extends WebSocketActivityBase implements Filter .request(Messages.Request.QueryAlbums) .addOption(Messages.Key.CATEGORY, categoryName) .addOption(Messages.Key.CATEGORY_ID, categoryId) - .addOption(Key.FILTER, filter) + .addOption(Key.FILTER, lastFilter) .build(); wss.send(message, socketClient, (SocketMessage response) -> adapter.setModel(response.getJsonArrayOption(Messages.Key.DATA))); } + + private final Debouncer filterDebouncer = new Debouncer(350) { + @Override + protected void onDebounced(String context) { + if (!isPaused()) { + requery(); + } + } + }; + private WebSocketService.Client socketClient = new WebSocketService.Client() { @Override public void onStateChanged(WebSocketService.State newState, WebSocketService.State oldState) { if (newState == WebSocketService.State.Connected) { + filterDebouncer.call(); requery(); } } diff --git a/src/musikdroid/app/src/main/java/io/casey/musikcube/remote/CategoryBrowseActivity.java b/src/musikdroid/app/src/main/java/io/casey/musikcube/remote/CategoryBrowseActivity.java index bb436ffdf..c7ff33f16 100644 --- a/src/musikdroid/app/src/main/java/io/casey/musikcube/remote/CategoryBrowseActivity.java +++ b/src/musikdroid/app/src/main/java/io/casey/musikcube/remote/CategoryBrowseActivity.java @@ -56,7 +56,7 @@ public class CategoryBrowseActivity extends WebSocketActivityBase implements Fil private String category; private Adapter adapter; - private String filter; + private String lastFilter; private TransportFragment transport; private int deepLinkType; @@ -102,8 +102,8 @@ public class CategoryBrowseActivity extends WebSocketActivityBase implements Fil @Override public void setFilter(String filter) { - this.filter = filter; - requery(); + this.lastFilter = filter; + this.filterDebouncer.call(); } @Override @@ -115,7 +115,7 @@ public class CategoryBrowseActivity extends WebSocketActivityBase implements Fil final SocketMessage request = SocketMessage.Builder .request(Messages.Request.QueryCategory) .addOption(Messages.Key.CATEGORY, category) - .addOption(Messages.Key.FILTER, filter) + .addOption(Messages.Key.FILTER, lastFilter) .build(); getWebSocketService().send(request, this.socketClient, (SocketMessage response) -> { @@ -126,10 +126,20 @@ public class CategoryBrowseActivity extends WebSocketActivityBase implements Fil }); } + private final Debouncer filterDebouncer = new Debouncer(350) { + @Override + protected void onDebounced(String caller) { + if (!isPaused()) { + requery(); + } + } + }; + private WebSocketService.Client socketClient = new WebSocketService.Client() { @Override public void onStateChanged(WebSocketService.State newState, WebSocketService.State oldState) { if (newState == WebSocketService.State.Connected) { + filterDebouncer.cancel(); requery(); } } diff --git a/src/musikdroid/app/src/main/java/io/casey/musikcube/remote/Debouncer.java b/src/musikdroid/app/src/main/java/io/casey/musikcube/remote/Debouncer.java new file mode 100644 index 000000000..899fdd905 --- /dev/null +++ b/src/musikdroid/app/src/main/java/io/casey/musikcube/remote/Debouncer.java @@ -0,0 +1,35 @@ +package io.casey.musikcube.remote; + +import android.os.Handler; +import android.os.Looper; + +public abstract class Debouncer { + private Handler handler = new Handler(Looper.getMainLooper()); + private T t = null; + private long delay; + + public Debouncer(long delay) { + this.delay = delay; + } + + public void call() { + handler.removeCallbacks(deferred); + handler.postDelayed(deferred, delay); + } + + public void call(T t) { + this.t = t; + handler.removeCallbacks(deferred); + handler.postDelayed(deferred, delay); + } + + public void cancel() { + handler.removeCallbacks(deferred); + } + + protected abstract void onDebounced(T caller); + + private Runnable deferred = () -> { + onDebounced(t); + }; +} diff --git a/src/musikdroid/app/src/main/java/io/casey/musikcube/remote/MainActivity.java b/src/musikdroid/app/src/main/java/io/casey/musikcube/remote/MainActivity.java index b635e1f27..6e2b64cb4 100644 --- a/src/musikdroid/app/src/main/java/io/casey/musikcube/remote/MainActivity.java +++ b/src/musikdroid/app/src/main/java/io/casey/musikcube/remote/MainActivity.java @@ -373,6 +373,13 @@ public class MainActivity extends WebSocketActivityBase { } } + private void clearUi() { + model.reset(); + albumArtModel = new AlbumArtModel(); + updateAlbumArt(); + rebindUi(); + } + private void setMetadataDisplayMode(DisplayMode mode) { if (metadataAnim1 != null) { metadataAnim1.cancel(); @@ -547,14 +554,12 @@ public class MainActivity extends WebSocketActivityBase { if (newState == WebSocketService.State.Connected) { wss.send(SocketMessage.Builder.request( Messages.Request.GetPlaybackOverview.toString()).build()); + + rebindUi(); } else if (newState == WebSocketService.State.Disconnected) { - model.reset(); - albumArtModel = new AlbumArtModel(); - updateAlbumArt(); + clearUi(); } - - rebindUi(); } @Override diff --git a/src/musikdroid/app/src/main/java/io/casey/musikcube/remote/TrackListActivity.java b/src/musikdroid/app/src/main/java/io/casey/musikcube/remote/TrackListActivity.java index 5cf407bbb..8685a7443 100644 --- a/src/musikdroid/app/src/main/java/io/casey/musikcube/remote/TrackListActivity.java +++ b/src/musikdroid/app/src/main/java/io/casey/musikcube/remote/TrackListActivity.java @@ -49,7 +49,7 @@ public class TrackListActivity extends WebSocketActivityBase implements Filterab private TransportFragment transport; private String categoryType; private long categoryId; - private String filter = ""; + private String lastFilter = ""; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { @@ -107,14 +107,15 @@ public class TrackListActivity extends WebSocketActivityBase implements Filterab @Override public void setFilter(String filter) { - this.filter = filter; - tracks.requery(); + this.lastFilter = filter; + this.filterDebouncer.call(); } private WebSocketService.Client socketServiceClient = new WebSocketService.Client() { @Override public void onStateChanged(WebSocketService.State newState, WebSocketService.State oldState) { if (newState == WebSocketService.State.Connected) { + filterDebouncer.cancel(); tracks.requery(); } } @@ -128,6 +129,15 @@ public class TrackListActivity extends WebSocketActivityBase implements Filterab } }; + private final Debouncer filterDebouncer = new Debouncer(350) { + @Override + protected void onDebounced(String caller) { + if (!isPaused()) { + tracks.requery(); + } + } + }; + private View.OnClickListener onItemClickListener = (View view) -> { int index = (Integer) view.getTag(); SocketMessage request; @@ -138,14 +148,14 @@ public class TrackListActivity extends WebSocketActivityBase implements Filterab .addOption(Messages.Key.CATEGORY, categoryType) .addOption(Messages.Key.ID, categoryId) .addOption(Messages.Key.INDEX, index) - .addOption(Messages.Key.FILTER, filter) + .addOption(Messages.Key.FILTER, lastFilter) .build(); } else { request = SocketMessage.Builder .request(Messages.Request.PlayAllTracks) .addOption(Messages.Key.INDEX, index) - .addOption(Messages.Key.FILTER, filter) + .addOption(Messages.Key.FILTER, lastFilter) .build(); } @@ -232,7 +242,7 @@ public class TrackListActivity extends WebSocketActivityBase implements Filterab .addOption(Messages.Key.CATEGORY, categoryType) .addOption(Messages.Key.ID, categoryId) .addOption(Messages.Key.COUNT_ONLY, true) - .addOption(Messages.Key.FILTER, filter) + .addOption(Messages.Key.FILTER, lastFilter) .build(); } @@ -244,7 +254,7 @@ public class TrackListActivity extends WebSocketActivityBase implements Filterab .addOption(Messages.Key.ID, categoryId) .addOption(Messages.Key.OFFSET, offset) .addOption(Messages.Key.LIMIT, limit) - .addOption(Messages.Key.FILTER, filter) + .addOption(Messages.Key.FILTER, lastFilter) .build(); } }; @@ -256,7 +266,7 @@ public class TrackListActivity extends WebSocketActivityBase implements Filterab public SocketMessage getRequeryMessage() { return SocketMessage.Builder .request(Messages.Request.QueryTracks) - .addOption(Messages.Key.FILTER, filter) + .addOption(Messages.Key.FILTER, lastFilter) .addOption(Messages.Key.COUNT_ONLY, true) .build(); } @@ -267,7 +277,7 @@ public class TrackListActivity extends WebSocketActivityBase implements Filterab .request(Messages.Request.QueryTracks) .addOption(Messages.Key.OFFSET, offset) .addOption(Messages.Key.LIMIT, limit) - .addOption(Messages.Key.FILTER, filter) + .addOption(Messages.Key.FILTER, lastFilter) .build(); } }; diff --git a/src/musikdroid/app/src/main/java/io/casey/musikcube/remote/WebSocketActivityBase.java b/src/musikdroid/app/src/main/java/io/casey/musikcube/remote/WebSocketActivityBase.java index 219614d8e..8dc8b9d0b 100644 --- a/src/musikdroid/app/src/main/java/io/casey/musikcube/remote/WebSocketActivityBase.java +++ b/src/musikdroid/app/src/main/java/io/casey/musikcube/remote/WebSocketActivityBase.java @@ -7,6 +7,7 @@ import android.view.KeyEvent; public abstract class WebSocketActivityBase extends AppCompatActivity { private WebSocketService wss; + private boolean paused = true; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { @@ -18,12 +19,14 @@ public abstract class WebSocketActivityBase extends AppCompatActivity { protected void onPause() { super.onPause(); this.wss.removeClient(getWebSocketServiceClient()); + this.paused = true; } @Override protected void onResume() { super.onResume(); this.wss.addClient(getWebSocketServiceClient()); + this.paused = false; } @Override @@ -49,6 +52,10 @@ public abstract class WebSocketActivityBase extends AppCompatActivity { return super.onKeyDown(keyCode, event); } + protected final boolean isPaused() { + return this.paused; + } + protected final WebSocketService getWebSocketService() { return this.wss; }