【问题标题】:Can I use Dagger 2's field injection in Kotlin?我可以在 Kotlin 中使用 Dagger 2 的场注入吗?
【发布时间】:2017-11-12 11:53:01
【问题描述】:

我发布了一个问题(Dagger 2 does not generate the component class (Android, Kotlin)),经过一些实验,似乎问题可能是由于 Kotlin 隐藏了该字段。

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

错误信息是,

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

theCoffee 在我的源代码中不是私有的。但我认为 Kotlin 可能正在翻译

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

转成Java代码

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

我可以在 Kotlin 中使用字段注入吗?

【问题讨论】:

    标签: kotlin dagger-2


    【解决方案1】:

    我认为 Kotlin 可能正在将 [...] 翻译成 [...] 的 Java 代码

    你是对的,这正是发生的事情。

    通常你不会在 Kotlin 中编写

    @Inject var coffee: Coffee? = null
    

    因为当您要访问咖啡时,它永远不会为空。换句话说,您将始终在访问对象的字段之前注入对象。这使得运营商 !! 多余,? 不必要。 Kotlin 有 lateinit 属性修饰符来表达这一点。

    @Inject lateinit var coffee: Coffee
    

    当您使用lateinit 时,生成的字段与其getter 和setter 具有相同的可见性,在本例中为public。这使它可以与 Dagger 一起使用。

    您可以通过查看生成的 Kotlin 字节码来查看结果。

    主菜单 > 工具 > Kotlin > 显示 Kotlin 字节码

    然而,更好的方法是注入类构造函数:

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

    在这种情况下,coffee 不是 var,不能重新分配。

    当框架为您创建实例时,注入构造函数不是一个选项,Android Activity 就是一个很好的例子。


    注意:使用限定符时,您必须在其上指定 field 注释目标:

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

    编辑:使用Dagger 2.25 or newer时不需要添加field目标。


    我可以在 Kotlin 中使用字段注入吗?

    是的,你可以。如上所述,字段注入实际上应用于lateinit 属性。

    但您可能对在 Kotlin 中生成和注入没有 getter/setter 的字段感兴趣。

    @JvmField @Inject
    var coffee: Coffee? = null
    

    【讨论】:

    • 其实在发这个问题之前我看到lateinit,但是如果我使用'lateinit',似乎我不能再使用字段注入而必须使用构造函数注入,对吗?错误消息是Coffee cannot be provided without an @Inject constructor or from an @Provides- or @Produces-annotated method.。那么,这不是让我的问题的答案变成“否”吗?
    • @DamnVegetables 该死,我完全错过了这个问题:D 查看更新的答案。 but if I use 'lateinit', it seemed that I could no longer use field injection but had to use constructor injection 现在我不确定你所说的 field injection 是什么意思。手动拨打MembersInjector?这适用于lateinit。就匕首而言,lateinit=field。
    • 谢谢。如果你不介意,Arabica 是从哪里来的?错误消息@Provides- or @Produces-annotated method 是否意味着为CoffeeShop 提供/生产?因为Coffee 的提供方法已经存在。 (完整的来源在我提到的问题中。)
    • @DamnVegetables Arabica 是由 custom qualifier 组成的。您现在可能不需要限定符。专注于让它发挥作用。关于错误:Dagger 需要注入val coffee: Coffee,为此它需要知道Coffee 的来源。正如错误提示,有两种方法。我认为user guide 解释得最好。
    猜你喜欢
    • 1970-01-01
    • 2019-10-27
    • 1970-01-01
    • 1970-01-01
    • 2018-03-08
    • 1970-01-01
    • 2017-07-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多