I have an editText which represent an input for a search criteria. I want to know if there is a way to detect when user stops editing this editText so I can query the db for data for my list. For example, if the user types "test" I want to be notified only after user has typed the word, not after user types each letter, like text watcher does. Do you have any ideas? I would avoid to use some timer to measure milliseconds elapsed between key pres events.
android editText: detect when user stops editing
Asked Answered
Can't you use spaces as a delimiter? Specify Regex in a TextWatcher and validate for spaces –
Aaronson
no, maybe the user does not press space key or maybe he types only half of a name and he expects to see the available results –
Bowhead
But then you want to use characters. Do you want to avoid multiple requests to your db while the user is typing? –
Aaronson
yes, I want to avoid multiple requests to your db while the user is typing –
Bowhead
I think you should then add a button that the user would click on to search. Any other method can get messy and cause problems. –
Aaronson
@Neil, just because it's probably a bad idea doesn't mean there aren't use cases where it makes sense. –
Lamartine
I'm just giving the best solution. I didn't say that there aren't cases that wouldn't work. Do you have a better solution? Please share it with us –
Aaronson
I'm not sure if it is better. Most likely what I gave him is the wrong design choice, but it fits the implementation he wants and asked for. –
Lamartine
Not incredibly elegant, but this should work.
Initializations:
long idle_min = 4000; // 4 seconds after user stops typing
long last_text_edit = 0;
Handler h = new Handler();
boolean already_queried = false;
Set up your runnable that will be called from the text watcher:
private Runnable input_finish_checker = new Runnable() {
public void run() {
if (System.currentTimeMillis() > (last_text_edit + idle_min - 500)) {
// user hasn't changed the EditText for longer than
// the min delay (with half second buffer window)
if (!already_queried) { // don't do this stuff twice.
already_queried = true;
do_stuff(); // your queries
}
}
}
};
Put this in your text watcher:
last_text_edit = System.currentTimeMillis();
h.postDelayed(input_finish_checker, idle_min);
it takes only few characters when i put it in textwatcher like when i type "Hello" then it takes only "He" –
Drucie
i got the solution of the problem. Actully every time it creates new thread so we need to stop the earlier thread For that we need to stop the earlier thread here is the function h.removeCallbacks(input_finish_checker); –
Drucie
First create the following field :
private Date _lastTypeTime = null;
Then make sure your your editText implements 'TextWatcher':
_editText.addTextChangedListener(this);
then, override the interface`s methods as follows:
@Override
public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3)
{
_lastTypeTime = new Date();
}
@Override
public void afterTextChanged(Editable arg0)
{
}
@Override
public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3)
{
// dispatch after done typing (1 sec after)
Timer t = new Timer();
TimerTask tt = new TimerTask()
{
@Override
public void run()
{
Date myRunTime = new Date();
if ((_lastTypeTime.getTime() + 1000) <= myRunTime.getTime())
{
post(new Runnable()
{
@Override
public void run()
{
Log.d("<tag>", "typing finished!!!");
}
});
}
else
{
Log.d("<tag>", "Canceled");
}
}
};
t.schedule(tt, 1000);
}
Thanks a lot @gor, this was by far the best solution ever :D –
Lacilacie
Good answer but I think you need the view to get the post working. –
Roomette
method
post
not exists –
Stubble 'post' method is available through extending a View (which is the example case) or by using a Handler –
Hua
Here's how you can detect event you are looking for.
Declarations and initialization:
private Timer timer = new Timer();
private final long DELAY = 1000; // in ms
Listener in e.g. onCreate()
EditText editText = (EditText) findViewById(R.id.editTextStopId);
editText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
@Override
public void onTextChanged(final CharSequence s, int start, int before,
int count) {
if(timer != null)
timer.cancel();
}
@Override
public void afterTextChanged(final Editable s) {
//avoid triggering event when text is too short
if (s.length() >= 3) {
timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
// TODO: do what you need here (refresh list)
// you will probably need to use
// runOnUiThread(Runnable action) for some specific
// actions
queryDB();
}
}, DELAY);
}
}
});
So, when text is changed the timer is starting to wait for any next changes to happen. When they occure timer is cancelled and then started once again.
This will certainly wait 1000m or whatever delay but then it will run queryDB() as many times as there are characters... –
Tomy
How is that possible? It will run only once, but there is a risk that writing another letter after the run() fired will fire it once again. To cope with that input can be temporarily disabled. –
Horseshoes
I have found that if you type "micro" really fast, the system will wait 1000ms, then it will run
queryDB()
two times one after another with no delay. That is what my tests showed at least and I copied it verbatim.. Put a log statement inside the run()
method and try it yourself? –
Tomy This is how I did and works for me!
long delay = 1000; // 1 seconds after user stops typing
long last_text_edit = 0;
Handler handler = new Handler();
private Runnable input_finish_checker = new Runnable() {
public void run() {
if (System.currentTimeMillis() > (last_text_edit + delay - 500)) {
// TODO: do what you need here
DoStaff();
}
}
};
EditText editText = (EditText) findViewById(R.id.editTextStopId);
editText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
@Override
public void onTextChanged(final CharSequence s, int start, int before,
int count) {
//You need to remove this to run only once
handler.removeCallbacks(input_finish_checker);
}
@Override
public void afterTextChanged(final Editable s) {
//avoid triggering event when text is empty
if (s.length() > 0) {
last_text_edit = System.currentTimeMillis();
handler.postDelayed(input_finish_checker, delay);
} else {
}
}
});
the easiest way to check if editText
is has text or NOT (only once) , do this :
private boolean newState;
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.somLayout);
edt.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void afterTextChanged(Editable editable) {
if (!editable.trim().isEmpty()) {
checkIsTyping(true);
} else {
checkIsTyping(false);
}
}
});
}
private void checkIsTyping(boolean typeState) {
if (newState != typeState) {
Toast.makeText(appCompatActivity, "typingState " + newState,
Toast.LENGTH_SHORT).show();
}
newState = typeState;
}
© 2022 - 2025 — McMap. All rights reserved.