Dagger将接口注入私有字段

3

我想在抽象类构造函数中注入接口实现,并在子类中使用它。

我遇到了编译时错误:

Error:Gradle: Dagger does not support injection into private fields
Error:Gradle: Example.A cannot be provided without an @Provides-annotated method.
Error:Gradle: Example.B cannot be provided without an @Inject constructor or from an @Provides-annotated method.
Error:Gradle: Execution failed for task ':app:compileDemoDebugJavaWithJavac'.
> Compilation failed; see the compiler error output for details.

Kotlin中的示例。

   object Example {
    interface IData {

        fun foo() {
        }
    }

    class Data : IData {

    }

    @Module
    class DataModel {
        @Provides
        fun data(): IData = Data()
    }

    @Singleton
    @Component(modules =
    arrayOf(DataModel::class)
    )
    interface Injector {
        fun inject(a: A)
        fun inject(b: B)
    }

    val graph: Injector = DaggerInjector.builder().
            dataModel(DataModel()).
            build()

    abstract class A {

        @Inject var data: IData ? = null

        public open fun setUp() {
            graph.inject(this)
        }
    }

    open class B : A() {

        override fun setUp() {
            super.setUp()
            data!!.foo()
        }
    }

    fun bar() {
        val a = B()
        a.setUp()
    }
}

版本:

  • com.android.tools.build:gradle:2.1.2
  • ext.kotlin_version = '1.0.3'
  • compile 'com.google.dagger:dagger:2.4'
  • provided 'org.glassfish:javax.annotation:10.0-b28'
  • kapt 'com.google.dagger:dagger-compiler:2.4'

以下是案例,反编译 Java 代码

  public static class A {
  @Inject
  @Nullable
  private Example.IData data;

  @Nullable
  protected final Example.IData getData() {
     return this.data;
  }

  protected final void setData(@Nullable Example.IData <set-?>) {
     this.data = <set-?>;
  }

  public void setUp() {
     Example.INSTANCE.getGraph().inject(this);
  }

}

1个回答

7

从错误信息看,我认为问题出在这一行代码:

@Inject var data: IData ? = null

该属性的后备字段为private,这就是错误提示的原因。通常使用lateinit关键字处理此类情况:
@Inject lateinit var data: IData

lateinit 是几个修饰符之一,它使用属性的访问级别(这里是 public)直接暴露后备字段,使其对由 Dagger 生成的类可见。


谢谢。我无法理解发生了什么。数据受到保护且可变。 - punksta
@StasShakirov,您附加的代码片段是在应用lateinit之后反编译的,对吗?如果您在lateinit之前对代码执行相同操作,您应该会看到这行代码:private Example.IData data;。由于Dagger不使用setter来填充@Inject字段,而是尝试直接访问该字段,因此它会在原始情况下抛出错误。这种可见性变化是lateinit的副作用(除了其在Kotlin中的主要含义之外),因为该修饰符最初是为了支持依赖注入而创建的。 - AndroidEx
我回答你的评论有点晚 :) 希望现在有意义了。 - AndroidEx
哈,有趣!我从未知道 lateinit 公开了支持字段。我只是会将 @Inject 移到该属性的 setter 中。 - Marcin Koziński

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接