Dagger does not support injection into private fields

这是因为在 Kotlin 中,Field 生成的 Java 代码都是都是带 getset 的,然后 Field 是要设置为 private 的,下面就是生成的代码

@Nullable
@Inject
private volatile DispatchingAndroidInjector androidInjector;

@Nullable
   public final DispatchingAndroidInjector getAndroidInjector() {
      return this.androidInjector;
   }

   public final void setAndroidInjector(@Nullable DispatchingAndroidInjector var1) {
      this.androidInjector = var1;
   }

这种情况我们有两种方法解决

第一种,让它变回 Java 原本的样子

增加 JvmField

@Inject
@JvmField
var androidInjector: DispatchingAndroidInjector<Any?>? = null

这样生成的代码就会变成

@Inject
@JvmField
@Nullable
public volatile DispatchingAndroidInjector androidInjector;

这样就完全没有问题了,但是这样会把属性暴露出去,不是很好。因为kotlin是没有包内属性的,你也改不了为包内属性。

第二种,设置 set 方法为 Inject

以为 dagger 是支持注入方法的,直接标记属性的 setter 方法也能解决这问题,代码如下

@Volatile
@set:Inject
var androidInjector: DispatchingAndroidInjector<Any?>? = null

对应的 Java代码就会变成这样

   @Nullable
   private DispatchingAndroidInjector androidInjector;

   @Nullable
   public final DispatchingAndroidInjector getAndroidInjector() {
      return this.androidInjector;
   }

   @Inject
   public final void setAndroidInjector(@Nullable DispatchingAndroidInjector var1) {
      this.androidInjector = var1;
   }

这是一个比较好的实现,不会影响原有的访问域,代码编写也比较方便

这里有个小问题
如果你在 Android Studio 3.5到 3.6 编译这个代码,会报下面这个错误

An exception occurred: java.lang.IllegalArgumentException: not a > valid name: Provider

但是,用命令行编译是没有问题的,所以我把 Android Studio 升级到 4.0,重新编译之后就没有这个问题。

上面没用,乖乖用 lateinit var 啥事都没有