Как работает синтаксис доступа к свойствам Kotlin для классов Java (т.е. EditText setText)?
Я пытаюсь переключить свой проект Android на Kotlin. У меня есть EditText
(подкласс TextView
), для которого я хочу установить подсказку и текст программно. Подсказка работает как положено. Для текста, однако, я получаю исключение несоответствия типов, если я пытаюсь сделать это, используя синтаксис Kotlin:
val test = EditText(context)
test.setHint("hint") // Lint message: "Use property access syntax"
test.hint = "hint" // ok
test.setText("text") // ok (no lint message)
test.text = "text" // Type mismatch: inferred type is kotlin.String but android.text.Editable! was expected
Если мы посмотрим на объявление, мы найдем идентичные подписи, унаследованные от TextView
:
public final void setHint(CharSequence hint)
public final void setText(CharSequence text)
У меня сложилось впечатление, что xy = z
было сокращением для x.setY(z)
но, очевидно, это впечатление было неправильным. setText()
рассматривается как обычный метод, а не как установщик, но какая разница между этими двумя методами, которая заставляет компилятор вести себя по-разному? Единственное, о чем я могу подумать, это то, что TextView
имеет свойство mHint
но я не думаю, что это может иметь место.
Еще одна вещь, которую я не совсем понимаю: откуда взялся android.text.Editable
? Нет соответствующего метода setText(Editable)
и нет открытого поля этого типа.
Ответы
Ответ 1
При генерации синтетического свойства пары Java getter/setter Kotlin сначала ищет геттер. Геттера достаточно, чтобы создать синтетическое свойство с типом геттера. С другой стороны, свойство не будет создано, если присутствует только сеттер.
При запуске сеттера создание свойства становится более сложным. Причина в том, что геттер и сеттер могут иметь различный тип. Более того, геттер и/или сеттер могут быть переопределены в подклассе.
В вашем случае класс TextView
содержит getter CharSequence getText()
и setter void setText(CharSequence)
. Если у вас есть переменная типа TextView
, ваш код будет работать нормально. Но у вас есть переменная типа EditText
. И класс EditText
содержит переопределенный getter Editable getText()
, что означает, что вы можете получить Editable
для EditText
и установить Editable
в EditText
. Поэтому Котлин разумно создает синтетическое свойство text
типа Editable
. Класс String
не является Editable
, поэтому вы не можете назначить экземпляр String
для свойства text
класса EditText
.
Ответ 2
Чтобы избежать несоответствия типов, вы можете использовать внутренний класс Factory класса Editable.
Итак, теперь вы можете сделать что-то вроде:
textview.text = Editable.Factory.getInstance().newEditable("your text")
Ответ 3
В качестве альтернативы вы можете написать расширение:
fun String.toEditable(): Editable = Editable.Factory.getInstance().newEditable(this)
Затем вы можете использовать его как таковой:
mEditText.text = myString.toEditable()
Ответ 4
android.text.Editable
происходит от getText()
. Мне кажется, что разрешение obj.text = value
в Котлине - двухэтапный процесс.
- Компилятор пытается найти свойство
text
или метод Java getText
, из которого он выводит тип свойства
- Для свойства inferred type компилятор пытается найти соответствующий набор свойств или метод Java
setText(PropertyType value)
Так как в 1. выведенном типе Editable
ошибка editText.text = "value"
не выполняется с ошибкой Type mismatch
.