Reputation: 614
Here is my TextWatcher
:
searchBox.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged( CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(final CharSequence charSequence, int i, int i1, int i2) {
ArrayList<ProductInformation> newList = new ArrayList<>();
for (ProductInformation info : currentList)
if (info.getName().contains(charSequence))
newList.add(info);
productListAdapter.setNewData(newList);
}
@Override
public void afterTextChanged(Editable editable) {
}
});
After adding this listener
to my editText
its lagging when typing .
I guess the problem is searching in list ( list has 40 to 60 items in it ) .
What can i do ?
Upvotes: 1
Views: 996
Reputation: 2487
A real-time text search has some requirements for better performance:
Requirement
You shouldn't start to search immediately because user typing speed is quite fast, and next result immediately overrides the last one. Multiple search process runs but only the last result will be shown is wasted on performance.
Try to make the search asynchronous, even if it's a network request or just a local search so it won't harm the UI and can be canceled easily.
Solution
Use Timer
and TimerTask
for delay and cancel during typing
private Timer mRequestDelayTimer;
private TimerTask mSearchTask;
@Override
public void onTextChanged(final CharSequence query, int i, int i1, int i2) {
if (mRequestDelayTimer != null)
mRequestDelayTimer.cancel();
// If you do a async search, stop it here
stopSearch();
mRequestDelayTimer = new Timer();
mSearchTask = new TimerTask() {
@Override
public void run() {
startSearch(query);
}
};
mRequestDelayTimer.schedule(mSearchTask, 500);
}
private synchronized void startSearch(String query) {
// This is not run in UI thread. Use activity.runOnUiThread if you want to update the UI
// Call an AsyncTask to do an async search or run a sync loop search here
//ArrayList<ProductInformation> newList = new ArrayList<>();
//for (ProductInformation info : currentList)
// if (info.getName().contains(charSequence))
// newList.add(info);
//productListAdapter.setNewData(newList);
}
Explanation
If each character typed in is within 500ms, it doesn't call startSearch because the timer keeps delaying.
If user rest for more than 500ms, startSearch
is called off the UI thread. Then if the user starts to type while the search is still in progress, it will be canceled.
If you are doing the search and update result in an ArrayAdapter
, it has a Filter
process built-in, you can custom it by overriding getFilter
. This filter automatically runs in the background, do the cancelation for each character enter, very handy. Ref: Custom getFilter in custom ArrayAdapter in android
Your actual implementation may be different, but the idea is the same
Upvotes: 1
Reputation: 1648
You can avoid lagging of search time with the logic that if time difference between two characters entered is greater than a specific time then you start searching in the list to update productListAdapter
and if not then stay idle.
Here is the source code:
startTime = System.currentTimeMillis();
endTime = System.currentTimeMillis();
searchBox.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged( CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(final CharSequence charSequence, int i, int i1, int i2) {
endTime = System.currentTimeMillis();
if(endTime - startTime >= 1000) {
ArrayList<ProductInformation> newList = new ArrayList<>();
for (ProductInformation info : currentList)
if (info.getName().contains(charSequence))
newList.add(info);
productListAdapter.setNewData(newList);
}
startTime = endTime;
}
@Override
public void afterTextChanged(Editable editable) {
}
});
Upvotes: 1