События TextWatcher запускаются несколько раз

У меня есть раздражающая проблема с TextWatcher. я искал в Интернете, но ничего не нашел. оцените, сможет ли кто-нибудь помочь мне.

По какой-то причине вызовы событий TextWatcher при одном изменении текста являются неустойчивыми. иногда они срабатывают один раз (как и должно быть), иногда два раза, а иногда и 3 раза. не знаю, почему, все это очень прямолинейно. также иногда параметр Editable на afterTextChanged() возвращает пустые значения в toString() и length().

ниже:

    private TextWatcher mSearchAddressTextChangeListener = new TextWatcher() {
        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) { }

        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) { }

        @Override
        public void afterTextChanged(Editable searchedAddress) {
           System.out.println("called multiple times.");   
        }
    };

внутри afterTextChanged()AsyncTask) im не вносит никаких изменений в текст или в представление EditText.

Я видел вопрос, заданный в События TextWatcher вызываются дважды, но im, у которых события срабатывают больше (или меньше), чем дважды.

В любом случае, оцените любую помощь.

EDIT: Я удалил содержимое afterTextChanged(), потому что эта проблема происходит даже без моего кода. что заставляет меня думать, что это ошибка. Ошибка возникает, когда "пробел" char вводится сразу после регулярного char (обработчики событий запускаются дважды) или когда "пробел" char после удаления обычного char (backspace. Обработчики событий срабатывают 3 раза). помощь по-прежнему будет оценена.

Ответ 1

У меня была такая же проблема, когда я нажал кнопку backspace с курсором в конце непрерывного текста, после того, как TextChange был вызван 3 раза: - Первый раз с правильной величиной s - Второй раз с четким значением - В третий раз с правильным значением снова

После многого поиска в Интернете я попытался изменить свой входной текст EditText на

android:inputType="textNoSuggestions"

Не спрашивайте меня, почему, но это сработало, afterTextChanged теперь вызывается только один раз.

Ответ 2

Согласно страницам разработчиков TextWatcher, если в Editable внесено изменение в TextWatcher, это вызовет далее вызывает все TextWatchers, связанные с этим Editable. Теперь, очевидно, ваш код не вызывает такого поведения.

Однако вполне возможно, что если по какой-либо причине система имеет TextWatcher на Editable, ситуация, о которой вы описываете, может произойти. "Почему", я слышу, как ты плачешь, "должно ли это случиться?"

Во-первых, классическая защита: нет причин, чтобы это не произошло, и, строго, код приложения должен быть написан, чтобы быть устойчивым к нему.

Во-вторых, я не могу это доказать, но я вполне мог представить, что в коде, который обрабатывает макет отображаемого текста в EditText, используется TextWatcher для обработки отображения текста на экране. Этот код может вставлять управляющие коды (которые вы не показываете) в Editable для обеспечения хороших разрывов строк и т.д. Он может даже обойти цикл несколько раз, чтобы получить все правильно, и вы можете получить свой первый звонок после того, как он выполнил все его...

ИЗМЕНИТЬ

Согласно комментарию @Learn OpenGL ES, вызов TextWatcher был бы нормальным для таких вещей, как автокоррекция.

Ответ 3

boolean isOnTextChanged = false;

@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}

@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
    isOnTextChanged = true;
}

@Override
public void afterTextChanged(Editable quantity) {
    if (isOnTextChanged) {
        isOnTextChanged = false;
       //dosomething
    }

Ответ 4

u может использовать логическую проверку, например:

    inputBoxNumberEt.addTextChangedListener(new TextWatcher() {

        boolean ignoreChange = false;

        @Override
        public void afterTextChanged(Editable s) {
        }

        @Override
        public void beforeTextChanged(CharSequence s, int start,
                                      int count, int after) {
        }

        @Override
        public void onTextChanged(CharSequence s, int start,
                                  int before, int count) {
            if (!ignoreChange) {
              ///Do your checks                    
                ignoreChange = true;
                inputBoxNumberEt.setText(string);
                inputBoxNumberEt.setSelection(inputBoxNumberEt.getText().length());
                ignoreChange = false;
            }
        }
    });

Ответ 5

Я перепробовал все решения, ответили на этот вопрос, ни один из них не работал для меня. Но после некоторых поисков я нашел этот пост. Использование RxJava, чтобы сделать дебат, работало хорошо для меня. Вот мое окончательное решение:

Добавьте зависимости RxJava в файл Gradle:

compile 'io.reactivex:rxandroid:1.0.1'
compile 'io.reactivex:rxjava:1.0.14'
compile 'com.artemzin.rxjava:proguard-rules:1.0.14.2'

Реализуйте свою тему:

PublishSubject<String> yourSubject = PublishSubject.create();
    yourSubject .debounce(100, TimeUnit.MILLISECONDS)
            .onBackpressureLatest()
            .subscribe(s -> {
                //Implements anything you want
            });

Используйте вашу тему в вашем TextWatcher:

TextWatcher myTextWatcher = new TextWatcher() {
    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
    }

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
        yourSubject.onNext(s.toString()); //apply here your subject
    }

    @Override
    public void afterTextChanged(Editable s) {
    }
};

Добавьте TextWatcher в прослушиватель EditText:

my_edit_text.addTextChangedListener(myTextWatcher);

Ответ 6

Для меня работал код ниже. Обратите внимание, что логическое значение было изменено после цикла условия if в методе afterTextChanged

        edittext.addTextChangedListener(new TextWatcher() 
        {
            boolean considerChange = false;

            public void beforeTextChanged(CharSequence cs, int start, int count, int after) {}

            public void onTextChanged(CharSequence cs, int start, int before, int count) {}

            public void afterTextChanged(Editable editable) 
            {
                if (considerChange) 
                { 
                    // your code here
                }
                considerChange = !considerChange; //see that boolean value is being changed after if loop
            }


        });