web-dev-qa-db-fra.com

Comment la syntaxe d'accès aux propriétés Kotlin fonctionne-t-elle pour les classes Java (par exemple, EditText setText)?

J'essaie de passer mon projet Android à Kotlin. J'ai une EditText (une sous-classe de TextView) pour laquelle je veux définir un conseil et un texte par programme. L'indice fonctionne comme prévu. Pour le texte, cependant, je reçois une exception d'incompatibilité de type si j'essaie de le faire à l'aide de la syntaxe 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

Si nous regardons la déclaration, nous trouverons des signatures identiques héritées de TextView:

    public final void setHint(CharSequence hint)

    public final void setText(CharSequence text)

J'avais l'impression que x.y = z était un raccourci pour x.setY(z) mais apparemment, cette impression était fausse. setText() est traité comme une méthode normale plutôt que comme un configurateur, mais quelle est la différence entre ces deux méthodes qui rend le compilateur se comporter différemment? La seule chose à laquelle je puisse penser est que TextView a une propriété mHint mais je ne pense pas que ce soit le cas.

Une autre chose que je ne comprends pas très bien, c’est d’où vient Android.text.Editable? Il n'y a pas de méthode setText(Editable) correspondante ni de champ public de ce type.

Merci.

18
SqueezyMo

Lors de la génération d'une propriété synthétique pour une paire d'accesseurs/fixateurs Java, Kotlin recherche d'abord un agent d'accesseur. Le getter est suffisant pour créer une propriété synthétique avec un type du getter. D'autre part, la propriété ne sera pas créée si seul un poseur est présent.

Quand un setter entre en jeu, la création de propriété devient plus difficile. La raison en est que le getter et le setter peuvent avoir un type différent. De plus, le getter et/ou le setter peuvent être remplacés dans une sous-classe.

Dans votre cas, la classe TextView contient une getter CharSequence getText() et une setter void setText(CharSequence). Si vous aviez une variable de type TextView, votre code fonctionnerait correctement. Mais vous avez une variable de type EditText. Et la classe EditText contient une fonction getter Editable getText() surchargée, ce qui signifie que vous pouvez obtenir une Editable pour une EditText et définir une Editable sur une EditText. Par conséquent, Kotlin crée raisonnablement une propriété synthétique text de type Editable. La classe String n'est pas Editable, c'est pourquoi vous ne pouvez pas affecter une instance String à la propriété text de la classe EditText.

40
Michael

Pour éviter les incompatibilités de types, vous pouvez utiliser la classe interne Factory de la classe Editable. Vous pouvez donc maintenant faire quelque chose comme: 

textview.text = Editable.Factory.getInstance().newEditable("your text")  
9

Le Android.text.Editable provient de la getText() . Il me semble que la résolution obj.text = value dans Kotlin est un processus en 2 étapes.

  1. Le compilateur essaie de trouver une propriété text ou une méthode Java getText à partir de laquelle il déduit le type de propriété
  2. Pour le type de propriété inférée, le compilateur essaie de trouver le configurateur de propriété ou la méthode Java correspondant. setText(PropertyType value)

Puisque dans le 1. le type inféré est Editable, le editText.text = "value" échoue avec l'erreur Type mismatch.

4
miensol

Sinon, vous pouvez écrire une extension:

fun String.toEditable(): Editable =  Editable.Factory.getInstance().newEditable(this)

Vous pouvez ensuite l'utiliser comme tel:

mEditText.text = myString.toEditable()
2
BNY