Как обновить тот же EditText с помощью TextWatcher?

В моем приложении для Android мне нужно реализовать интерфейс TextWatcher для реализации onTextChanged. Проблема в том, что я хочу обновить тот же EditText с помощью дополнительной строки. Когда я пытаюсь это сделать, программа завершается.

 final EditText ET = (EditText) findViewById(R.id.editText1);
 ET.addTextChangedListener(new TextWatcher() {

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count)
        {
            try
            {
                 ET.setText("***"+ s.toString());
                 ET.setSelection(s.length());
            }
            catch(Exception e)
            {
                Log.v("State", e.getMessage());
            }
        }

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

        }

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

Моя программа завершается, и даже я пытаюсь поймать исключение, как в моем коде, но оно завершается. Кто-нибудь знает, почему это происходит и как я могу этого добиться? Спасибо.


person JibW    schedule 29.02.2012    source источник
comment
When I try to do this the program terminates. это в основном означает, что вы должны предоставить трассировку стека, которую можно найти в LogCat. Это бы нам очень помогло!   -  person WarrenFaith    schedule 29.02.2012


Ответы (4)


Содержимое TextView не редактируется в событии onTextChanged.

Вместо этого вам нужно обработать событие afterTextChanged, чтобы иметь возможность вносить изменения в текст.

Для более подробного объяснения см.: Android TextWatcher.afterTextChanged vs TextWatcher.onTextChanged


Примечание. Ошибка onTextChanged

Очевидно, вы вызываете бесконечный цикл, постоянно меняя текст в событии afterTextChanged.

Из ссылки:

public abstract void afterTextChanged (Editable s)
Этот метод вызывается, чтобы уведомить вас о том, что где-то внутри s текст был изменен. Вполне законно вносить дальнейшие изменения в s из этого обратного вызова, но будьте осторожны, чтобы не попасть в бесконечный цикл, потому что любые сделанные вами изменения приведут к повторному рекурсивному вызову этого метода. ...

  • Предложение 1: если можете, проверьте, является ли s уже тем, что вы хотите, когда событие инициировано.

    @Override
    public void afterTextChanged(Editable s)
    {    
        if( !s.equalsIngoreCase("smth defined previously"))
             s = "smth defined previously";              
    }
    
  • Предложение 2: если вам нужно сделать более сложные вещи (форматирование, проверка), вы можете использовать метод synchronized, как в это сообщение.

Примечание 2. Форматирование ввода как частично скрытого с n звездочками до последних 4 символов (***four)

Вы можете использовать что-то вроде этого в предложении 1:

    @Override
    public void afterTextChanged(Editable s)
    {    
       String sText = ET.getText().toString()

        if( !isFormatted(sText))
             s = format(sText);              
    }
    bool isFormatted(String s)
    {
     //check if s is already formatted
    }

    string format(String s)
    {
      //format s & return
    }
person Orkun Ozen    schedule 29.02.2012
comment
HI Zorkun, я попытался добавить тот же код в событие afterTextChanged(Editable s)... Тем не менее он завершается... Знаете ли вы какой-либо другой альтернативный способ сделать это? Спасибо - person JibW; 29.02.2012
comment
S можно редактировать в afterTextChanged(Editable s). Но все же он не может быть назначен EditText. - person JibW; 29.02.2012
comment
Да, это правда. Это вызывает бесконечный цикл, постоянно меняя текст в событии afterTextChanged. Дело в том, что я хочу скрыть первые буквы в EditText с некоторым символом как * и позволить видеть только последние 4 символа... - person JibW; 29.02.2012
comment
Спасибо... Да, можно ограничивать его выполнение снова и снова с помощью простого условия if... Большое спасибо за ваше время и помощь...!!!! - person JibW; 29.02.2012
comment
Невозможно преобразовать из String в Editable. - person IgorGanapolsky; 17.04.2012

поздний ответ, если кто-то смотрит так, как я это сделал.

  • установить addTextChangedListener изначально
  • в одном из обратных вызовов (скажем, onTextChanged()) удалить addTextChangedListener
  • Все еще заинтересованы в получении обновлений, добавьте его снова.

вот код.

editText.addTextChangedListener(new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            Log.d("log", "before");
        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {

            Log.d("log", "after");
            editText.removeTextChangedListener(this);

            ediText.setText("text you wanted to put");

            editText.addTextChangedListener(this);

        }

        @Override
        public void afterTextChanged(Editable s) {


        }
    });
person Irfan    schedule 12.04.2017

В дополнение к ответу Зорткуна (где код примера сильно нарушен), вот как вы должны использовать afterTextChanged() для обновления того же EditText:

editText.addTextChangedListener(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) {    
    }

    @Override
    public void afterTextChanged(Editable editable) {        
        if (!editable.toString().startsWith("***")) {
            editable.insert(0, "***");
        }        
    }
});

Ознакомьтесь с интерфейсом Editable, чтобы узнать о других операциях помимо insert().

Обратите внимание, что легко попасть в бесконечный цикл (изменения, которые вы делаете, снова вызывают afterTextChanged()), поэтому обычно вы делаете свои изменения внутри условия if, как указано выше.

Как указано в afterTextChanged() javadocs:

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

person Jonik    schedule 02.08.2016

Вот фрагмент, который работал для меня

etPhoneNumber.addTextChangedListener(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) {}

        @Override
        public void afterTextChanged(Editable s) {
            if (!s.toString().equals(Utils.getFormattedNumber(s.toString()))) {
                s.replace(0, s.length(), Utils.getFormattedNumber(s.toString()));
            }
        }
    });

где Utils.getFormattedPhoneNumber() — ваш метод, возвращающий отформатированное число

person James Gathu    schedule 27.02.2018