Added code to debounce filtering on the client-side so we don't send a

bunch of extra requests to the backend when searching.
This commit is contained in:
casey langen 2017-02-18 13:55:42 -08:00
parent 264f564243
commit 0fd1e0bff9
6 changed files with 100 additions and 22 deletions

View File

@ -61,7 +61,7 @@ public class AlbumBrowseActivity extends WebSocketActivityBase implements Filter
private TransportFragment transport; private TransportFragment transport;
private String categoryName; private String categoryName;
private long categoryId; private long categoryId;
private String filter = ""; private String lastFilter = "";
@Override @Override
protected void onCreate(@Nullable Bundle savedInstanceState) { protected void onCreate(@Nullable Bundle savedInstanceState) {
@ -97,8 +97,8 @@ public class AlbumBrowseActivity extends WebSocketActivityBase implements Filter
@Override @Override
public void setFilter(String filter) { public void setFilter(String filter) {
this.filter = filter; this.lastFilter = filter;
requery(); filterDebouncer.call(filter);
} }
@Override @Override
@ -122,17 +122,28 @@ public class AlbumBrowseActivity extends WebSocketActivityBase implements Filter
.request(Messages.Request.QueryAlbums) .request(Messages.Request.QueryAlbums)
.addOption(Messages.Key.CATEGORY, categoryName) .addOption(Messages.Key.CATEGORY, categoryName)
.addOption(Messages.Key.CATEGORY_ID, categoryId) .addOption(Messages.Key.CATEGORY_ID, categoryId)
.addOption(Key.FILTER, filter) .addOption(Key.FILTER, lastFilter)
.build(); .build();
wss.send(message, socketClient, (SocketMessage response) -> wss.send(message, socketClient, (SocketMessage response) ->
adapter.setModel(response.getJsonArrayOption(Messages.Key.DATA))); adapter.setModel(response.getJsonArrayOption(Messages.Key.DATA)));
} }
private final Debouncer<String> filterDebouncer = new Debouncer<String>(350) {
@Override
protected void onDebounced(String context) {
if (!isPaused()) {
requery();
}
}
};
private WebSocketService.Client socketClient = new WebSocketService.Client() { private WebSocketService.Client socketClient = new WebSocketService.Client() {
@Override @Override
public void onStateChanged(WebSocketService.State newState, WebSocketService.State oldState) { public void onStateChanged(WebSocketService.State newState, WebSocketService.State oldState) {
if (newState == WebSocketService.State.Connected) { if (newState == WebSocketService.State.Connected) {
filterDebouncer.call();
requery(); requery();
} }
} }

View File

@ -56,7 +56,7 @@ public class CategoryBrowseActivity extends WebSocketActivityBase implements Fil
private String category; private String category;
private Adapter adapter; private Adapter adapter;
private String filter; private String lastFilter;
private TransportFragment transport; private TransportFragment transport;
private int deepLinkType; private int deepLinkType;
@ -102,8 +102,8 @@ public class CategoryBrowseActivity extends WebSocketActivityBase implements Fil
@Override @Override
public void setFilter(String filter) { public void setFilter(String filter) {
this.filter = filter; this.lastFilter = filter;
requery(); this.filterDebouncer.call();
} }
@Override @Override
@ -115,7 +115,7 @@ public class CategoryBrowseActivity extends WebSocketActivityBase implements Fil
final SocketMessage request = SocketMessage.Builder final SocketMessage request = SocketMessage.Builder
.request(Messages.Request.QueryCategory) .request(Messages.Request.QueryCategory)
.addOption(Messages.Key.CATEGORY, category) .addOption(Messages.Key.CATEGORY, category)
.addOption(Messages.Key.FILTER, filter) .addOption(Messages.Key.FILTER, lastFilter)
.build(); .build();
getWebSocketService().send(request, this.socketClient, (SocketMessage response) -> { getWebSocketService().send(request, this.socketClient, (SocketMessage response) -> {
@ -126,10 +126,20 @@ public class CategoryBrowseActivity extends WebSocketActivityBase implements Fil
}); });
} }
private final Debouncer<String> filterDebouncer = new Debouncer<String>(350) {
@Override
protected void onDebounced(String caller) {
if (!isPaused()) {
requery();
}
}
};
private WebSocketService.Client socketClient = new WebSocketService.Client() { private WebSocketService.Client socketClient = new WebSocketService.Client() {
@Override @Override
public void onStateChanged(WebSocketService.State newState, WebSocketService.State oldState) { public void onStateChanged(WebSocketService.State newState, WebSocketService.State oldState) {
if (newState == WebSocketService.State.Connected) { if (newState == WebSocketService.State.Connected) {
filterDebouncer.cancel();
requery(); requery();
} }
} }

View File

@ -0,0 +1,35 @@
package io.casey.musikcube.remote;
import android.os.Handler;
import android.os.Looper;
public abstract class Debouncer<T> {
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);
};
}

View File

@ -373,6 +373,13 @@ public class MainActivity extends WebSocketActivityBase {
} }
} }
private void clearUi() {
model.reset();
albumArtModel = new AlbumArtModel();
updateAlbumArt();
rebindUi();
}
private void setMetadataDisplayMode(DisplayMode mode) { private void setMetadataDisplayMode(DisplayMode mode) {
if (metadataAnim1 != null) { if (metadataAnim1 != null) {
metadataAnim1.cancel(); metadataAnim1.cancel();
@ -547,14 +554,12 @@ public class MainActivity extends WebSocketActivityBase {
if (newState == WebSocketService.State.Connected) { if (newState == WebSocketService.State.Connected) {
wss.send(SocketMessage.Builder.request( wss.send(SocketMessage.Builder.request(
Messages.Request.GetPlaybackOverview.toString()).build()); Messages.Request.GetPlaybackOverview.toString()).build());
rebindUi();
} }
else if (newState == WebSocketService.State.Disconnected) { else if (newState == WebSocketService.State.Disconnected) {
model.reset(); clearUi();
albumArtModel = new AlbumArtModel();
updateAlbumArt();
} }
rebindUi();
} }
@Override @Override

View File

@ -49,7 +49,7 @@ public class TrackListActivity extends WebSocketActivityBase implements Filterab
private TransportFragment transport; private TransportFragment transport;
private String categoryType; private String categoryType;
private long categoryId; private long categoryId;
private String filter = ""; private String lastFilter = "";
@Override @Override
protected void onCreate(@Nullable Bundle savedInstanceState) { protected void onCreate(@Nullable Bundle savedInstanceState) {
@ -107,14 +107,15 @@ public class TrackListActivity extends WebSocketActivityBase implements Filterab
@Override @Override
public void setFilter(String filter) { public void setFilter(String filter) {
this.filter = filter; this.lastFilter = filter;
tracks.requery(); this.filterDebouncer.call();
} }
private WebSocketService.Client socketServiceClient = new WebSocketService.Client() { private WebSocketService.Client socketServiceClient = new WebSocketService.Client() {
@Override @Override
public void onStateChanged(WebSocketService.State newState, WebSocketService.State oldState) { public void onStateChanged(WebSocketService.State newState, WebSocketService.State oldState) {
if (newState == WebSocketService.State.Connected) { if (newState == WebSocketService.State.Connected) {
filterDebouncer.cancel();
tracks.requery(); tracks.requery();
} }
} }
@ -128,6 +129,15 @@ public class TrackListActivity extends WebSocketActivityBase implements Filterab
} }
}; };
private final Debouncer<String> filterDebouncer = new Debouncer<String>(350) {
@Override
protected void onDebounced(String caller) {
if (!isPaused()) {
tracks.requery();
}
}
};
private View.OnClickListener onItemClickListener = (View view) -> { private View.OnClickListener onItemClickListener = (View view) -> {
int index = (Integer) view.getTag(); int index = (Integer) view.getTag();
SocketMessage request; SocketMessage request;
@ -138,14 +148,14 @@ public class TrackListActivity extends WebSocketActivityBase implements Filterab
.addOption(Messages.Key.CATEGORY, categoryType) .addOption(Messages.Key.CATEGORY, categoryType)
.addOption(Messages.Key.ID, categoryId) .addOption(Messages.Key.ID, categoryId)
.addOption(Messages.Key.INDEX, index) .addOption(Messages.Key.INDEX, index)
.addOption(Messages.Key.FILTER, filter) .addOption(Messages.Key.FILTER, lastFilter)
.build(); .build();
} }
else { else {
request = SocketMessage.Builder request = SocketMessage.Builder
.request(Messages.Request.PlayAllTracks) .request(Messages.Request.PlayAllTracks)
.addOption(Messages.Key.INDEX, index) .addOption(Messages.Key.INDEX, index)
.addOption(Messages.Key.FILTER, filter) .addOption(Messages.Key.FILTER, lastFilter)
.build(); .build();
} }
@ -232,7 +242,7 @@ public class TrackListActivity extends WebSocketActivityBase implements Filterab
.addOption(Messages.Key.CATEGORY, categoryType) .addOption(Messages.Key.CATEGORY, categoryType)
.addOption(Messages.Key.ID, categoryId) .addOption(Messages.Key.ID, categoryId)
.addOption(Messages.Key.COUNT_ONLY, true) .addOption(Messages.Key.COUNT_ONLY, true)
.addOption(Messages.Key.FILTER, filter) .addOption(Messages.Key.FILTER, lastFilter)
.build(); .build();
} }
@ -244,7 +254,7 @@ public class TrackListActivity extends WebSocketActivityBase implements Filterab
.addOption(Messages.Key.ID, categoryId) .addOption(Messages.Key.ID, categoryId)
.addOption(Messages.Key.OFFSET, offset) .addOption(Messages.Key.OFFSET, offset)
.addOption(Messages.Key.LIMIT, limit) .addOption(Messages.Key.LIMIT, limit)
.addOption(Messages.Key.FILTER, filter) .addOption(Messages.Key.FILTER, lastFilter)
.build(); .build();
} }
}; };
@ -256,7 +266,7 @@ public class TrackListActivity extends WebSocketActivityBase implements Filterab
public SocketMessage getRequeryMessage() { public SocketMessage getRequeryMessage() {
return SocketMessage.Builder return SocketMessage.Builder
.request(Messages.Request.QueryTracks) .request(Messages.Request.QueryTracks)
.addOption(Messages.Key.FILTER, filter) .addOption(Messages.Key.FILTER, lastFilter)
.addOption(Messages.Key.COUNT_ONLY, true) .addOption(Messages.Key.COUNT_ONLY, true)
.build(); .build();
} }
@ -267,7 +277,7 @@ public class TrackListActivity extends WebSocketActivityBase implements Filterab
.request(Messages.Request.QueryTracks) .request(Messages.Request.QueryTracks)
.addOption(Messages.Key.OFFSET, offset) .addOption(Messages.Key.OFFSET, offset)
.addOption(Messages.Key.LIMIT, limit) .addOption(Messages.Key.LIMIT, limit)
.addOption(Messages.Key.FILTER, filter) .addOption(Messages.Key.FILTER, lastFilter)
.build(); .build();
} }
}; };

View File

@ -7,6 +7,7 @@ import android.view.KeyEvent;
public abstract class WebSocketActivityBase extends AppCompatActivity { public abstract class WebSocketActivityBase extends AppCompatActivity {
private WebSocketService wss; private WebSocketService wss;
private boolean paused = true;
@Override @Override
protected void onCreate(@Nullable Bundle savedInstanceState) { protected void onCreate(@Nullable Bundle savedInstanceState) {
@ -18,12 +19,14 @@ public abstract class WebSocketActivityBase extends AppCompatActivity {
protected void onPause() { protected void onPause() {
super.onPause(); super.onPause();
this.wss.removeClient(getWebSocketServiceClient()); this.wss.removeClient(getWebSocketServiceClient());
this.paused = true;
} }
@Override @Override
protected void onResume() { protected void onResume() {
super.onResume(); super.onResume();
this.wss.addClient(getWebSocketServiceClient()); this.wss.addClient(getWebSocketServiceClient());
this.paused = false;
} }
@Override @Override
@ -49,6 +52,10 @@ public abstract class WebSocketActivityBase extends AppCompatActivity {
return super.onKeyDown(keyCode, event); return super.onKeyDown(keyCode, event);
} }
protected final boolean isPaused() {
return this.paused;
}
protected final WebSocketService getWebSocketService() { protected final WebSocketService getWebSocketService() {
return this.wss; return this.wss;
} }