Skip to content

Commit bba53eb

Browse files
committed
Use debouncer for realtime searching/filtering
Introduce a 200 ms delay for each queries to enable the user to finish writing the complete query before processing the query. This significantly reduces the amount of processing time as it ignores the unfinished queries (which also improves power consumption). The 200 ms delay is considered because the processing time in most cases is about 10-40 ms depending on the type of device, totaling 225 ms in average case. This number is about 125 ms worse than the human perception, but considering the rendering and response time, it was considered to be adequate. Signed-off-by: Muntashir Al-Islam <muntashirakon@riseup.net>
1 parent 329b8dc commit bba53eb

13 files changed

Lines changed: 220 additions & 116 deletions

app/src/main/java/io/github/muntashirakon/AppManager/debloat/DebloaterActivity.java

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
import io.github.muntashirakon.AppManager.batchops.BatchQueueItem;
3131
import io.github.muntashirakon.AppManager.batchops.struct.BatchFreezeOptions;
3232
import io.github.muntashirakon.AppManager.batchops.struct.IBatchOpOptions;
33-
import io.github.muntashirakon.AppManager.misc.AdvancedSearchView;
33+
import io.github.muntashirakon.AppManager.misc.SearchViewDebouncer;
3434
import io.github.muntashirakon.AppManager.profiles.AddToProfileDialogFragment;
3535
import io.github.muntashirakon.AppManager.settings.Prefs;
3636
import io.github.muntashirakon.AppManager.utils.StoragePermission;
@@ -40,13 +40,13 @@
4040
import io.github.muntashirakon.widget.RecyclerView;
4141

4242
public class DebloaterActivity extends BaseActivity implements MultiSelectionView.OnSelectionChangeListener,
43-
MultiSelectionActionsView.OnItemSelectedListener, AdvancedSearchView.OnQueryTextListener,
44-
MultiSelectionView.OnSelectionModeChangeListener {
43+
MultiSelectionActionsView.OnItemSelectedListener, MultiSelectionView.OnSelectionModeChangeListener {
4544
DebloaterViewModel viewModel;
4645

4746
private LinearProgressIndicator mProgressIndicator;
4847
private MultiSelectionView mMultiSelectionView;
4948
private DebloaterRecyclerViewAdapter mAdapter;
49+
private SearchViewDebouncer mSearchDebouncer;
5050

5151
private final StoragePermission mStoragePermission = StoragePermission.init(this);
5252
private final BroadcastReceiver mBatchOpsBroadCastReceiver = new BroadcastReceiver() {
@@ -78,7 +78,12 @@ protected void onAuthenticated(@Nullable Bundle savedInstanceState) {
7878
if (actionBar != null) {
7979
actionBar.setDisplayHomeAsUpEnabled(true);
8080
actionBar.setDisplayShowCustomEnabled(true);
81-
UIUtils.setupAdvancedSearchView(actionBar, this);
81+
mSearchDebouncer = new SearchViewDebouncer(SearchViewDebouncer.DELAY_STANDARD);
82+
mSearchDebouncer.bindAdvanced(UIUtils.setupAdvancedSearchView(actionBar), (query, type) -> {
83+
if (viewModel != null) {
84+
viewModel.setQuery(query, type);
85+
}
86+
});
8287
}
8388
viewModel = new ViewModelProvider(this).get(DebloaterViewModel.class);
8489

@@ -116,6 +121,14 @@ protected void onPause() {
116121
unregisterReceiver(mBatchOpsBroadCastReceiver);
117122
}
118123

124+
@Override
125+
protected void onDestroy() {
126+
super.onDestroy();
127+
if (mSearchDebouncer != null) {
128+
mSearchDebouncer.unbind();
129+
}
130+
}
131+
119132
@Override
120133
public boolean onCreateOptionsMenu(Menu menu) {
121134
getMenuInflater().inflate(R.menu.activity_debloater_actions, menu);
@@ -183,17 +196,6 @@ public boolean onNavigationItemSelected(@NonNull MenuItem item) {
183196
return true;
184197
}
185198

186-
@Override
187-
public boolean onQueryTextChange(String newText, int type) {
188-
viewModel.setQuery(newText, type);
189-
return true;
190-
}
191-
192-
@Override
193-
public boolean onQueryTextSubmit(String query, int type) {
194-
return false;
195-
}
196-
197199
private void showFreezeUnfreezeDialog(int freezeType) {
198200
View view = View.inflate(this, R.layout.item_checkbox, null);
199201
MaterialCheckBox checkBox = view.findViewById(R.id.checkbox);

app/src/main/java/io/github/muntashirakon/AppManager/details/AppDetailsActivity.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ protected void onAuthenticated(@Nullable Bundle savedInstanceState) {
156156
ActionBar actionBar = getSupportActionBar();
157157
if (actionBar != null) {
158158
actionBar.setDisplayShowCustomEnabled(true);
159-
searchView = UIUtils.setupAdvancedSearchView(actionBar, null);
159+
searchView = UIUtils.setupAdvancedSearchView(actionBar);
160160
}
161161
mViewPager = findViewById(R.id.pager);
162162
TabLayout tabLayout = findViewById(R.id.tab_layout);

app/src/main/java/io/github/muntashirakon/AppManager/details/AppDetailsComponentsFragment.java

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -201,27 +201,20 @@ public void onPause() {
201201
@Override
202202
public void onResume() {
203203
super.onResume();
204-
if (activity.searchView != null) {
205-
if (!activity.searchView.isShown()) {
206-
activity.searchView.setVisibility(View.VISIBLE);
207-
}
208-
activity.searchView.setOnQueryTextListener(this);
209-
if (viewModel != null) {
210-
int sortOrder = viewModel.getSortOrder(mNeededProperty);
211-
String searchQuery = viewModel.getSearchQuery();
212-
if (sortOrder != mSortOrder || !Objects.equals(searchQuery, mSearchQuery)) {
213-
viewModel.filterAndSortItems(mNeededProperty);
214-
}
204+
if (viewModel != null) {
205+
int sortOrder = viewModel.getSortOrder(mNeededProperty);
206+
String searchQuery = viewModel.getSearchQuery();
207+
if (sortOrder != mSortOrder || !Objects.equals(searchQuery, mSearchQuery)) {
208+
viewModel.filterAndSortItems(mNeededProperty);
215209
}
216210
}
217211
}
218212

219213
@Override
220-
public boolean onQueryTextChange(String searchQuery, int type) {
214+
public void search(String searchQuery, int type) {
221215
if (viewModel != null) {
222216
viewModel.setSearchQuery(searchQuery, type, mNeededProperty);
223217
}
224-
return true;
225218
}
226219

227220
private void updateBlockMenuItem(int status) {

app/src/main/java/io/github/muntashirakon/AppManager/details/AppDetailsFragment.java

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,15 @@
2525

2626
import io.github.muntashirakon.AppManager.R;
2727
import io.github.muntashirakon.AppManager.misc.AdvancedSearchView;
28+
import io.github.muntashirakon.AppManager.misc.SearchViewDebouncer;
2829
import io.github.muntashirakon.AppManager.utils.UIUtils;
2930
import io.github.muntashirakon.AppManager.utils.appearance.ColorCodes;
3031
import io.github.muntashirakon.view.ProgressIndicatorCompat;
3132
import io.github.muntashirakon.widget.MaterialAlertView;
3233
import io.github.muntashirakon.widget.RecyclerView;
3334
import io.github.muntashirakon.widget.SwipeRefreshLayout;
3435

35-
public abstract class AppDetailsFragment extends Fragment implements AdvancedSearchView.OnQueryTextListener,
36-
SwipeRefreshLayout.OnRefreshListener, MenuProvider {
36+
public abstract class AppDetailsFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener, MenuProvider {
3737
@IntDef(value = {
3838
APP_INFO,
3939
ACTIVITIES,
@@ -108,6 +108,7 @@ public abstract class AppDetailsFragment extends Fragment implements AdvancedSea
108108
protected TextView emptyView;
109109
@Nullable
110110
protected AppDetailsViewModel viewModel;
111+
private SearchViewDebouncer mSearchDebouncer;
111112

112113
protected int colorQueryStringHighlight;
113114

@@ -119,6 +120,7 @@ public void onCreate(@Nullable Bundle savedInstanceState) {
119120
viewModel = new ViewModelProvider(activity).get(AppDetailsViewModel.class);
120121
packageManager = activity.getPackageManager();
121122
colorQueryStringHighlight = ColorCodes.getQueryStringHighlightColor(activity);
123+
mSearchDebouncer = new SearchViewDebouncer(SearchViewDebouncer.DELAY_STANDARD);
122124
}
123125

124126
@Nullable
@@ -153,6 +155,21 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat
153155
public void onResume() {
154156
super.onResume();
155157
swipeRefresh.setEnabled(true);
158+
AdvancedSearchView searchView = activity.searchView;
159+
if (searchView != null) {
160+
if (this instanceof AppDetailsComponentsFragment || this instanceof AppDetailsPermissionsFragment) {
161+
if (!searchView.isShown()) {
162+
searchView.setVisibility(View.VISIBLE);
163+
}
164+
if (mSearchDebouncer != null) {
165+
mSearchDebouncer.bindAdvanced(searchView, this::search);
166+
}
167+
} else {
168+
if (searchView.isShown()) {
169+
searchView.setVisibility(View.GONE);
170+
}
171+
}
172+
}
156173
}
157174

158175
@CallSuper
@@ -170,8 +187,14 @@ public void onDestroyView() {
170187
super.onDestroyView();
171188
}
172189

190+
@CallSuper
173191
@Override
174-
public boolean onQueryTextSubmit(String query, int type) {
175-
return false;
192+
public void onDestroy() {
193+
super.onDestroy();
194+
if (mSearchDebouncer != null) {
195+
mSearchDebouncer.unbind();
196+
}
176197
}
198+
199+
protected abstract void search(String query, int type);
177200
}

app/src/main/java/io/github/muntashirakon/AppManager/details/AppDetailsOtherFragment.java

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -118,19 +118,10 @@ public boolean onMenuItemSelected(@NonNull MenuItem item) {
118118
}
119119

120120
@Override
121-
public void onResume() {
122-
super.onResume();
123-
if (activity.searchView != null) {
124-
activity.searchView.setVisibility(View.GONE);
125-
}
126-
}
127-
128-
@Override
129-
public boolean onQueryTextChange(String searchQuery, int type) {
121+
public void search(String searchQuery, int type) {
130122
if (viewModel != null) {
131123
viewModel.setSearchQuery(searchQuery, type, mNeededProperty);
132124
}
133-
return true;
134125
}
135126

136127
private void refreshDetails() {

app/src/main/java/io/github/muntashirakon/AppManager/details/AppDetailsOverlaysFragment.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,6 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat
9898
alertView.show();
9999
} else alertView.hide();
100100
});
101-
102101
}
103102

104103
@Override
@@ -134,11 +133,10 @@ public void onRefresh() {
134133
}
135134

136135
@Override
137-
public boolean onQueryTextChange(String newText, int type) {
136+
protected void search(String query, int type) {
138137
if (viewModel != null) {
139-
viewModel.setSearchQuery(newText, type, OVERLAYS);
138+
viewModel.setSearchQuery(query, type, OVERLAYS);
140139
}
141-
return true;
142140
}
143141

144142
private class AppDetailsRecyclerAdapter extends RecyclerView.Adapter<AppDetailsRecyclerAdapter.ViewHolder> {

app/src/main/java/io/github/muntashirakon/AppManager/details/AppDetailsPermissionsFragment.java

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -297,27 +297,20 @@ public void onPause() {
297297
@Override
298298
public void onResume() {
299299
super.onResume();
300-
if (activity.searchView != null) {
301-
if (!activity.searchView.isShown()) {
302-
activity.searchView.setVisibility(View.VISIBLE);
303-
}
304-
activity.searchView.setOnQueryTextListener(this);
305-
if (viewModel != null) {
306-
int sortOrder = viewModel.getSortOrder(mNeededProperty);
307-
String searchQuery = viewModel.getSearchQuery();
308-
if (sortOrder != mSortOrder || !Objects.equals(searchQuery, mSearchQuery)) {
309-
viewModel.filterAndSortItems(mNeededProperty);
310-
}
300+
if (viewModel != null) {
301+
int sortOrder = viewModel.getSortOrder(mNeededProperty);
302+
String searchQuery = viewModel.getSearchQuery();
303+
if (sortOrder != mSortOrder || !Objects.equals(searchQuery, mSearchQuery)) {
304+
viewModel.filterAndSortItems(mNeededProperty);
311305
}
312306
}
313307
}
314308

315309
@Override
316-
public boolean onQueryTextChange(String searchQuery, int type) {
310+
public void search(String searchQuery, int type) {
317311
if (viewModel != null) {
318312
viewModel.setSearchQuery(searchQuery, type, mNeededProperty);
319313
}
320-
return true;
321314
}
322315

323316
private int getNotFoundString(@PermissionProperty int index) {

app/src/main/java/io/github/muntashirakon/AppManager/details/info/AppInfoFragment.java

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -653,12 +653,6 @@ public void onMenuClosed(@NonNull Menu menu) {
653653
}
654654
}
655655

656-
@Override
657-
public void onStart() {
658-
super.onStart();
659-
if (mActivity.searchView != null) mActivity.searchView.setVisibility(View.GONE);
660-
}
661-
662656
@Override
663657
public void onRefresh() {
664658
mSwipeRefresh.setRefreshing(false);

app/src/main/java/io/github/muntashirakon/AppManager/main/MainActivity.java

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
import io.github.muntashirakon.AppManager.misc.AdvancedSearchView;
6969
import io.github.muntashirakon.AppManager.misc.HelpActivity;
7070
import io.github.muntashirakon.AppManager.misc.LabsActivity;
71+
import io.github.muntashirakon.AppManager.misc.SearchViewDebouncer;
7172
import io.github.muntashirakon.AppManager.oneclickops.OneClickOpsActivity;
7273
import io.github.muntashirakon.AppManager.profiles.AddToProfileDialogFragment;
7374
import io.github.muntashirakon.AppManager.profiles.ProfilesActivity;
@@ -93,8 +94,8 @@
9394
import io.github.muntashirakon.widget.MultiSelectionView;
9495
import io.github.muntashirakon.widget.SwipeRefreshLayout;
9596

96-
public class MainActivity extends BaseActivity implements AdvancedSearchView.OnQueryTextListener,
97-
SwipeRefreshLayout.OnRefreshListener, MultiSelectionActionsView.OnItemSelectedListener,
97+
public class MainActivity extends BaseActivity implements SwipeRefreshLayout.OnRefreshListener,
98+
MultiSelectionActionsView.OnItemSelectedListener,
9899
MultiSelectionView.OnSelectionModeChangeListener {
99100
private static final String PACKAGE_NAME_APK_UPDATER = "com.apkupdater";
100101
private static final String ACTIVITY_NAME_APK_UPDATER = "com.apkupdater.activity.MainActivity";
@@ -105,6 +106,7 @@ public class MainActivity extends BaseActivity implements AdvancedSearchView.OnQ
105106

106107
private MainRecyclerAdapter mAdapter;
107108
private AdvancedSearchView mSearchView;
109+
private SearchViewDebouncer mSearchDebouncer;
108110
private LinearProgressIndicator mProgressIndicator;
109111
private SwipeRefreshLayout mSwipeRefresh;
110112
private MultiSelectionView mMultiSelectionView;
@@ -205,16 +207,18 @@ protected void onAuthenticated(Bundle savedInstanceState) {
205207
if (actionBar != null) {
206208
actionBar.setDisplayShowCustomEnabled(true);
207209
actionBar.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE);
208-
AdvancedSearchView searchView = new AdvancedSearchView(actionBar.getThemedContext());
209-
searchView.setId(R.id.action_search);
210-
searchView.setOnQueryTextListener(this);
210+
mSearchView = new AdvancedSearchView(actionBar.getThemedContext());
211+
mSearchView.setId(R.id.action_search);
211212
// Set layout params
212213
ActionBar.LayoutParams layoutParams = new ActionBar.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
213214
ViewGroup.LayoutParams.WRAP_CONTENT);
214215
layoutParams.gravity = Gravity.CENTER;
215-
actionBar.setCustomView(searchView, layoutParams);
216-
mSearchView = searchView;
216+
actionBar.setCustomView(mSearchView, layoutParams);
217217
mSearchView.setIconifiedByDefault(false);
218+
mSearchDebouncer = new SearchViewDebouncer(SearchViewDebouncer.DELAY_STANDARD);
219+
mSearchDebouncer.bindAdvanced(mSearchView, (query, type) -> {
220+
if (viewModel != null) viewModel.setSearchQuery(query, type);
221+
});
218222
// Check for market://search/?q=<query>
219223
Uri marketUri = getIntent().getData();
220224
if (marketUri != null && "market".equals(marketUri.getScheme()) && "search".equals(marketUri.getHost())) {
@@ -556,6 +560,14 @@ protected void onPause() {
556560
unregisterReceiver(mBatchOpsBroadCastReceiver);
557561
}
558562

563+
@Override
564+
protected void onDestroy() {
565+
super.onDestroy();
566+
if (mSearchDebouncer != null) {
567+
mSearchDebouncer.unbind();
568+
}
569+
}
570+
559571
private void displayChangelogIfRequired() {
560572
if (!AppPref.getBoolean(AppPref.PrefKey.PREF_DISPLAY_CHANGELOG_BOOL)) {
561573
return;
@@ -641,15 +653,4 @@ void showProgressIndicator(boolean show) {
641653
if (show) mProgressIndicator.show();
642654
else mProgressIndicator.hide();
643655
}
644-
645-
@Override
646-
public boolean onQueryTextChange(String searchQuery, @AdvancedSearchView.SearchType int type) {
647-
if (viewModel != null) viewModel.setSearchQuery(searchQuery, type);
648-
return true;
649-
}
650-
651-
@Override
652-
public boolean onQueryTextSubmit(String query, int type) {
653-
return false;
654-
}
655656
}

0 commit comments

Comments
 (0)