How can I change the EditText text without triggering the Text Watcher?

user1143767 picture user1143767 · Feb 21, 2012 · Viewed 60.1k times · Source

I have an EditText field with a Customer Text Watcher on it. In a piece of code I need to change the value in the EditText which I do using .setText("whatever").

The problem is as soon as I make that change the afterTextChanged method gets called which created an infinite loop. How can I change the text without it triggering afterTextChanged?

I need the text in the afterTextChanged method so don't suggest removing the TextWatcher.

Answer

Willi Mentzel picture Willi Mentzel · Oct 15, 2015

Short answer

You can check which View currently has the focus to distinguish between user and program triggered events.

EditText myEditText = (EditText) findViewById(R.id.myEditText);

myEditText.addTextChangedListener(new TextWatcher() {

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
        if (myEditText.hasFocus()) {
            // is only executed if the EditText was directly changed by the user
        }
    }

    //...
});

Long answer

As an addition to the short answer: In case myEditText already has the focus when you programmatically change the text you should call clearFocus(), then you call setText(...) and after you you re-request the focus. It would be a good idea to put that in a utility function:

void updateText(EditText editText, String text) {
    boolean focussed = editText.hasFocus();
    if (focussed) {
        editText.clearFocus();
    }
    editText.setText(text);
    if (focussed) {
        editText.requestFocus();
    }
}

For Kotlin:

Since Kotlin supports extension functions your utility function could look like this:

fun EditText.updateText(text: String) {
    val focussed = hasFocus()
    if (focussed) {
        clearFocus()
    }
    setText(text)
    if (focussed) {
        requestFocus()
    }
}