I'm trying to switch my Android project to Kotlin. I have an EditText
(a subclass of TextView
) for which I want to set a hint and text programmatically. The hint works as expected. For text, though, I'm getting a type mismatch exception if I try to do it using Kotlin setter syntax:
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
If we look at the declaration, we'll find identical signatures inherited from TextView
:
public final void setHint(CharSequence hint)
public final void setText(CharSequence text)
I had an impression that x.y = z
was a shortcut for x.setY(z)
but apparently that impression was wrong. setText()
is treated as a normal method rather than a setter, but what's the difference between these two methods that makes the compiler behave differently? The only one I can think of is that TextView
has an mHint
property but I don't think it might be the case.
Another thing I don't quite understand is, where does android.text.Editable
come from? There is no corresponding setText(Editable)
method, nor is there a public field of this type.
Thanks.
Alternatively you could write an extension:
You can then use it as such:
When generating a synthetic property for a Java getter/setter pair Kotlin first looks for a getter. The getter is enough to create a synthetic property with a type of the getter. On the other hand the property will not be created if only a setter presents.
When a setter comes into play property creation becomes more difficult. The reason is that the getter and the setter may have different type. Moreover, the getter and/or the setter may be overridden in a subclass.
In your case the
TextView
class contains a getterCharSequence getText()
and a settervoid setText(CharSequence)
. If you had a variable of typeTextView
your code would work fine. But you have a variable of typeEditText
. And theEditText
class contains an overridden getterEditable getText()
, which means that you can get anEditable
for anEditText
and set anEditable
to anEditText
. Therefore, Kotlin reasonably creates a synthetic propertytext
of typeEditable
. TheString
class is notEditable
, that's why you cannot assign aString
instance to thetext
property of theEditText
class.The
android.text.Editable
comes from thegetText()
. It appears to me that theobj.text = value
resolution in Kotlin is 2 step process.text
property or Java methodgetText
from which it infers the property typesetText(PropertyType value)
Since in the 1. the inferred type is
Editable
theeditText.text = "value"
fails withType mismatch
error.To avoid type mismatch, you can use the Factory inner class of Editable class. So you can do now something like: