#android #android-edittext #android-textwatcher
#Android #android-edittext #android-textwatcher
Вопрос:
Я использую EditText
там, где я хочу задать текст или позволить пользователю вводить что-то в него. Я хотел сделать его «all-caps», поэтому я реализовал функцию capitalize для my TextWatcher
.
Вы можете входить и выходить из экрана с помощью этого EditText
и TextWatcher
несколько раз переходить туда и обратно, переключая экраны — это означает, что я должен правильно зарегистрироваться и отменить TextWatcher
EditText
регистрацию после события ввода / вывода экрана.
Я заметил, что если я вхожу и покидаю экран несколько раз подряд, после 5-го ввода все мое приложение зависает — значит, что-то блокирует поток пользовательского интерфейса.
При более глубоком исследовании я обнаружил, что если я позвоню editText.setText("some string")
, это вызовет моего afterTextChanged
слушателя несколько раз. При 5-м вводе он запускал его примерно 50 раз подряд, что вызывало блокировку потока пользовательского интерфейса.
Как это можно исправить или это ошибка на стороне Android?
Код: инициализация экрана при вводе:
initEditTextListener()
App.log("FormScreen - setData")
formFirstEt?.setText(item.name)
private var inputWatcher: TextWatcher? = null
private fun initEditTextListener(){
formFirstEt?.onEditorAction{
formInputValidation(this.text.toString(), formFirstEt, App.getString("form_empty"), App.getString("form_empty_reason"))
validateData()
formSecondEt?.let { s -> if (s.isEnabled) s.requestFocus() }
}
inputWatcher = object : TextWatcher {
override fun afterTextChanged(s: Editable?) {
App.log("FormScreen - initEditTextListener - afterTextChanged")
validateData()
}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
App.log("FormScreen - initEditTextListener - onTextChanged")
validateData()
formFirstEt?.let { et -> onFormFirstInputChanged(s.toString(), this, et)}
}
}
inputWatcher?.let {formFirstEt?.addTextChangedListener(it)}
}
Функция преобразования всех заголовков (не должна запускать TextWatcher)
fun onFormFirstInputChanged(s: String, tv: TextWatcher, et: EditText) {
et.removeTextChangedListener(tv)
if (isFirstInputValid(s)) {
with(et) {
text.clear()
append(s.toUpperCase(Locale.getDefault()))
setSelection(s.length)
}
} else {
val substring = s.substring(0, s.length - 1)
with(et) {
text.clear()
append(substring.toUpperCase(Locale.getDefault()))
setSelection(substring.length)
}
}
et.addTextChangedListener(tv)
}
Очистка экрана перед выходом:
formFirstEt?.setText("")
inputWatcher?.let { formFirstEt?.removeTextChangedListener(it) }
inputWatcher = null
Журналы:
-- First time screen enter ---
2021-01-14 11:24:50.324 1136-1136/? I/Project: FormScreen - setData
2021-01-14 11:24:50.458 1136-1136/? I/Project: FormScreen - initEditTextListener - onTextChanged
2021-01-14 11:24:50.460 1136-1136/? I/Project: FormScreen - initEditTextListener - afterTextChanged
2021-01-14 11:24:52.838 1136-1136/? I/Project: FormScreen - initEditTextListener - onTextChanged
2021-01-14 11:24:52.841 1136-1136/? I/Project: FormScreen - initEditTextListener - afterTextChanged
-- Second time screen enter --
2021-01-14 11:24:56.324 1136-1136/? I/Project: FormScreen - setData
2021-01-14 11:24:56.366 1136-1136/? I/Project: FormScreen - initEditTextListener - onTextChanged
2021-01-14 11:24:56.367 1136-1136/? I/Project: FormScreen - initEditTextListener - onTextChanged
2021-01-14 11:24:56.368 1136-1136/? I/Project: FormScreen - initEditTextListener - afterTextChanged
2021-01-14 11:24:56.368 1136-1136/? I/Project: FormScreen - initEditTextListener - onTextChanged
2021-01-14 11:24:56.369 1136-1136/? I/Project: FormScreen - initEditTextListener - afterTextChanged
2021-01-14 11:24:56.369 1136-1136/? I/Project: FormScreen - initEditTextListener - onTextChanged
2021-01-14 11:24:56.370 1136-1136/? I/Project: FormScreen - initEditTextListener - onTextChanged
2021-01-14 11:24:56.370 1136-1136/? I/Project: FormScreen - initEditTextListener - afterTextChanged
2021-01-14 11:24:56.371 1136-1136/? I/Project: FormScreen - initEditTextListener - onTextChanged
2021-01-14 11:24:56.372 1136-1136/? I/Project: FormScreen - initEditTextListener - afterTextChanged
2021-01-14 11:24:56.372 1136-1136/? I/Project: FormScreen - initEditTextListener - afterTextChanged
2021-01-14 11:24:56.373 1136-1136/? I/Project: FormScreen - initEditTextListener - afterTextChanged
ОБНОВЛЕНИЕ:
Это какое-то поведение Kotlin. Проблема была в formFirstEt?.setText("")
том, что я ожидал, что он добавит пустую строку EditText
, но, по-видимому, он добавляет символ-терминатор. Kotlin не может распознать, что String
это, но char array
по умолчанию с
символом в конце. Этот массив символов вызывает какое-то странное поведение внутри встроенной setText
функции, которая рассылает спам afterTextChanged
Исправить:
//type declaration String is important without it it will not work
val emptyString: String = ""
formFirstEt?.setText(emptyString)
Комментарии:
1. У меня было что-то подобное, но не уверен, что это ваш случай. Мое решение состояло в том, чтобы зарегистрировать слушателя только onResume
2. Упомянутое исправление. Странное поведение 🙂
3. @Bek Потому что ничто не помешает пользователю нажать Shift на клавиатуре и отключить функцию capslock.
Ответ №1:
Здесь та же проблема. У меня есть DialogFragment
, где я использую a TextInputEditText
с наблюдателем. Если я addTextChangedListener
в onCreateView
(обычно ожидается при использовании a DialogFragment
), то слушатель срабатывает либо один, либо несколько раз за нажатие клавиши (случайным образом).
Даже использование локальной переменной watcherEnabled
для обеспечения того, чтобы форматирование введенного значения не приводило к повторному запуску наблюдателя. сбой.
Вместо этого попытался переместить назначение наблюдателя onResume
. Это кажется совершенно нелепым и неправильным, но, похоже, решило проблему.
Также обратите внимание, что средство просмотра текста запускается несколько раз только при использовании компьютерной клавиатуры для ввода текста в эмулятор. Когда я использую клавиатуру эмулятора, наблюдатель, похоже, не дает сбоев. Это МОЖЕТ указывать на то, что ошибка связана исключительно с эмулятором.