EditText: различать изменение текста с помощью setText() или ввода с клавиатуры

У меня есть EditText View, который редактируется setText() из моего кода и пользователем через (мягкую/твердую) клавиатуру и, если возможно, с помощью речевого ввода. Я хочу обрабатывать ввод, сделанный моим кодом, по-другому, чем обычный пользовательский ввод: при входе пользователя происходит внутреннее событие. Но я не знаю, как отличить их обоих. Раньше - при разработке на эмуляторе я использовал метод onKeyDown(), чтобы поймать пользовательский ввод. Однако при тестировании на реальном устройстве я узнал, что onKeyDown() не запускается с мягкого ввода клавиатуры. Кроме того, речевой ввод не был бы признан этим, хотя я считаю, что это незначительный недостаток. Так что решение для меня не вариант.

С другой стороны, существует метод onTextChanged(), но это срабатывает как с помощью setText(), так и с клавиатуры. Итак, как я могу различать оба метода, или какой метод вызывается только пользователем, но не при использовании setText(), поэтому я могу его переписать?

Ответ 1

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

Ответ 2

Я считаю, что Android не позволяет различать программно и вручную введенный текст. Единственное обходное решение для вас использовать какую-либо sla, которая будет указывать, когда тест был установлен вашим кодом, потому что вы всегда знаете, когда вызываете setText().

Ответ 3

Вы можете использовать флаг для дифференциации.

((EditText) rootView.findViewById(R.id.editText1)).addTextChangedListener(new TextWatcher() {
        public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) {
        }

        public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) {
        }

        public void afterTextChanged(Editable editable) {
            update(true);
        }
    });            

private boolean updating = false;

private void update(boolean multiply) {
    if(updating){
        return;
    }
    updating = true;
    EditText editText1 = (EditText) getView().findViewById(R.id.editText1);
    editText1.setText("XXX");
    updating = false;
}

Ответ 4

У меня возникала эта проблема при повороте устройства. Мой editText находится внутри диалогового окна. Вот как я это решил:

editText.addTextChangedListener(
    new TextWatcher() {

        @Override
        public void afterTextChanged(Editable s) {
            String newValue = s.toString();

           String oldValue = (String) editText.getTag();

            if (newValue.length() > 0) {
                editText.setTag(newValue);
            }

            boolean itReallyChanged = oldValue != null && !newValue.equals(oldValue) && !newValue.isEmpty();
            if (itReallyChanged) {
                // Pretty sure the user genuinely changed this value,
                // not the device rotation
            }
        }
    }
);