Buda Gavril
Buda Gavril

Reputation: 21657

android editText: detect when user stops editing

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.

Upvotes: 6

Views: 10077

Answers (5)

mohammadReza Abiri
mohammadReza Abiri

Reputation: 1799

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;
    
        }

Upvotes: 0

ThetNaing Mizo
ThetNaing Mizo

Reputation: 4089

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 {

        }
    }
});

Upvotes: 2

ZimaXXX
ZimaXXX

Reputation: 1253

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.

Upvotes: 6

gor
gor

Reputation: 1056

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);
}

Upvotes: 7

eski
eski

Reputation: 7915

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); 

Upvotes: 10

Related Questions