android editText: detect when user stops editing
Asked Answered
B

5

6

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.

Bowhead answered 19/3, 2013 at 10:20 Comment(8)
Can't you use spaces as a delimiter? Specify Regex in a TextWatcher and validate for spacesAaronson
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 resultsBowhead
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 typingBowhead
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 usAaronson
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
L
10

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); 
Lamartine answered 19/3, 2013 at 10:56 Comment(2)
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
H
7

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);
}
Hua answered 5/6, 2013 at 16:5 Comment(4)
Thanks a lot @gor, this was by far the best solution ever :DLacilacie
Good answer but I think you need the view to get the post working.Roomette
method post not existsStubble
'post' method is available through extending a View (which is the example case) or by using a HandlerHua
H
6

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.

Horseshoes answered 20/2, 2015 at 9:40 Comment(3)
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
I
2

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 {

        }
    }
});
Inglebert answered 22/7, 2016 at 10:21 Comment(0)
F
0

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;
    
        }
Feudality answered 1/9, 2020 at 10:59 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.