Reputation: 1138
In a AutoCompleteTextView I want to show the auto complete list after there is a pause of 1 sec by user in typing. I tried using handler
handler.postDelayed( new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
if ( text.length() >= 3 ) {
// do something
} else if ( text.length() == 0 ) {
// do something
}
}
}, 1000 );
This code is a part of onTextChanged. So what it is happening is whenever there is a text change at that moment postDelayed is called and inside code will be called after a second. So how can I prevent that so the inner code is only called when there is a puase of 1 sec by user in typing.
e.g: If I type Ind (pause of 1 sec) then inner code execute should happen. But I type India then inner code should not execute for Ind, Indi, India. Need your suggestions.
Upvotes: 1
Views: 321
Reputation: 7826
I just stood at the same problem.
I am calling Googles Geocode suggestion API onTextChanged() and that caused many issues.
Users typing would cause masses of API requests, most of them not required and that uses up the API (costs money) and reduces the experience the user receives from the app.
I considered the solutions here but I did not like any of them in the end, they seemed unclean or like a hack.
I did not want to make further calls into the UI to get the current value of the View (again) or check system times.
The original question actually already solves the problem, it just causes multiple runnables to be alive when a user types.
So the question should be: "How to remove my anonymous runnable before it causes trouble ?"
All you have to do it use the original approach (the delayed call using the anonymous runnable) and whenever the onTextChanged function is called you REMOVE any previous runnables.
You can also extend the code and check if the value really changed (like using global previous value String) so the runnable is not killed if the user entered a char and removed it again.
So all you need to do:
1. Make the Handler a variable of the class instead of creating it inside the onTextChanged.
2. At the begin of onTextChanged remove the runnables from the handler
Here is a fully functional example:
Handler onchangeHandler = new Handler();
String last_onTextChanged=""; // may speed up some cases of user input, can be removed
@Override
public void onTextChanged(CharSequence charSequence, int i, int i2, int i3)
{
final String value = charSequence.toString();
if (value.length() < 3) {autoCompleteAdapter.clear();return;} // threshold of 3 chars
if (!last_onTextChanged.equals(value))
onchangeHandler.removeCallbacksAndMessages(null);
else
return;
last_onTextChanged=value;
onchangeHandler.postDelayed(new Runnable()
{
@Override
public void run()
{
// RUN CODE HERE, fill your autoCompleteAdapter etc.
}
},800);
}
Upvotes: 1
Reputation: 723
you can also cancel the previous Runnable
msg in message queue first in onTextChanged()
Upvotes: 0
Reputation: 4835
Create two static variables holding timestamps.
lastTimeStamp
and currentTimeStamp
, then you can do something like this:
@Override
public void run() {
if (currentTimeStamp - lastTimeStamp > 1000) {
// TODO Auto-generated method stub
if ( text.length() >= 3 ) {
// do something
} else if ( text.length() == 0 ) {
// do something
}
}
}
New approach:
At the beginning of your onTextChanged method, put a current TimeStamp in a class-variable.
Thereafter create an AsyncTask in the onTextChanged, which is just doing a
Thread.sleep(1000)
in the doInBackground-method.
Then you make an if-statement in the postExcute method, checking if the difference between TimeStamp in the class-variable and the current TimeStamp, if this is larger than 1000 post your handler.
Upvotes: 2
Reputation: 644
There are 2 options:
Use Timer and invoke cancel() on previous tasks when you are going to run the next one.
Extend Runnable and pass in a string for this autocompletion. If this string is not equal to current string in view (that means user changed the string), then you should not display autocompletion.
Code example:
abstract class MyRunnable {
private String str;
public MyRunnable(String str) {
this.str = str;
}
}
...
handler.postDelayed(new MyRunnable(currentViewStr) {
@Override
public void run() {
if (currentViewStr.equals(str)) {
// show autocompletion
}
}
}, 1000);
Upvotes: 0