web-dev-qa-db-fra.com

Puis-je utiliser l'injection de champ de Dagger 2 dans Kotlin?

J'ai posté une question ( Dagger 2 ne génère pas la classe de composants (Android, Kotlin) ), et après quelques expériences, il semble que le problème pourrait être dû au fait que Kotlin cache le champ.

class CoffeeShop {
    @Inject
    var theCoffee: Coffee? = null
}

Le message d'erreur est,

:app:kaptDebugKotline: ...\CoffeeShop.Java:7:
error: Dagger does not support injection into private fields
e:     private ....Coffee theCoffee;

theCoffee n'était pas privé dans mon code source. Mais je pense que Kotlin peut traduire

class CoffeeShop {
    @Inject
    var theCoffee: Coffee? = null
}

dans Java code de

class CoffeeShop {
    @Inject
    private Coffee theCoffee = null;
    public Coffee getTheCoffee();
    public void setTheCoffee();
}

Puis-je utiliser l'injection de terrain dans Kotlin?

17
Damn Vegetables

Je pense que Kotlin peut traduire [...] en Java code de [...]

Et vous auriez raison, c'est exactement ce qui se passe.

En général, dans Kotlin, vous n'écrivez pas

@Inject var coffee: Coffee? = null

car lorsque vous allez accéder au café, il ne sera jamais nul. En d'autres termes, vous injecterez toujours l'objet avant d'accéder à ses champs. Cela fait que les opérateurs !! redondant et ? inutile. Kotlin a le modificateur de propriété lateinit pour exprimer cela.

@Inject lateinit var coffee: Coffee

Lorsque vous utilisez lateinit, le champ généré a la même visibilité que son getter et son setter, dans ce cas public. Cela le fait fonctionner avec Dagger.

Vous pouvez voir le résultat en affichant le bytecode Kotlin généré.

Menu principal> Outils> Kotlin> Afficher le bytecode Kotlin

Cependant, une approche encore meilleure consisterait à injecter le constructeur de classe:

class CoffeeShop @Inject constructor(val coffee: Coffee) {
    //...
}

Dans ce cas, coffee n'est pas var et ne peut pas être réaffecté.

L'injection de constructeur n'est pas une option lorsque l'instance est créée pour vous par un framework, l'activité Android est un bon exemple.


Remarque: Lorsque vous utilisez des qualificatifs, vous devez spécifier field cible d'annotation sur eux:

@Inject @field:Named("Arabica") @field:Arabica
lateinit var coffee: Coffee

Puis-je utiliser l'injection de terrain dans Kotlin?

Oui, vous pouvez. Comme expliqué ci-dessus, l'injection de champs est en fait appliquée pour les propriétés lateinit.

Mais vous étiez probablement intéressé par la génération et l'injection de champs sans getter/setter dans Kotlin.

@JvmField @Inject
var coffee: Coffee? = null
39
Eugen Pechanec