初探Dagger2遇到的小坑

来源:互联网 发布:阿里云提供的服务 编辑:程序博客网 时间:2024/06/05 23:06

编译没错,为什么就是注入不了

//非常简单的一个活动class MainActivity : AppCompatActivity() {    @Inject    lateinit var a: String//待注入的变量    override fun onCreate(savedInstanceState: Bundle?) {        super.onCreate(savedInstanceState)        setContentView(R.layout.activity_main)        DaggerMainComponent.builder()                .mainModule(MainModule())                .build()                .inject(this)//注入        Log.d("=============", a)//打印看看结果    }}//提供字符串的module@Moduleclass MainModule {    @Provides    fun provideString(): String = "123"}@Component(modules = arrayOf(MainModule::class))interface MainComponent {    fun inject(activity: Activity)}

貌似操作都没错呀,然后结果如下:
Error: lateinit property a has not been initialized

所以这是为什么呢,还是看看Dagger生成的Inject方法是怎么工作的吧,说不定从这能找到答案

@Override  public void inject(Activity activity) {    MembersInjectors.<Activity>noOp().injectMembers(activity);  }

上面就是生成的inject方法了,显然要往injectMembers里面挖

//跳进来发现这是个空方法,那就一定有他的实现类了void injectMembers(T instance);//==========  实现1  ===========@Override  public void injectMembers(MainActivity instance) {    if (instance == null) {      throw new NullPointerException("Cannot inject members into a null reference");    }    instance.a = aProvider.get();  }//==========  实现2  ===========@Override public void injectMembers(Object instance) {      checkNotNull(instance);    }

可以看到,实现1中就对我们要注入的字符串a进行了赋值,而实现2中只是检查了一下目标类是不是空的。而实现1的对象是这样(<Activity>noOp())才能拿到的

//正确MembersInjectors.<MainActivity>noOp().injectMembers(activity);//错误MembersInjectors.<Activity>noOp().injectMembers(activity);

也就是说我们的inject方法参数写错了,只要吧MainComopnentinject的参数改为MainActivity就好了

@Component(modules = arrayOf(MainModule::class))interface MainComponent {    fun inject(activity: MainActivity)}

再跑一下:=============: 123

为什么我的单例会报错

@Moduleclass MainModule {    @Provides    @Singleton//单例??    fun provideString(): String = "123"}

把Module中的provide方法加上@Singleton注解后就是单例了?,编译一下…

Error:Execution failed for task ‘:app:kaptDebugKotlin’.
Internal compiler error. See log for more details

再看看Gradle Console中的日志:

Component (unscoped) may not reference scoped bindings

原来,对应的Comopnent要加上同样的标记才可以

@Singleton@Component(modules = arrayOf(MainModule::class))interface MainComponent {    fun inject(activity: MainActivity)}

再跑一下,编译通过了

再来看看@Singleton

@Scope@Documented@Retention(RUNTIME)public @interface Singleton {}

原来Singleton是一种作用域注解,Component和Module中的provide方法作用域注解相同才能实现单例

什么时候要在构建Component的时候传入Module

之前是这样写的,中间传入了Module

DaggerMainComponent.builder()                .mainModule(MainModule())                .build()                .inject(this)

把它去掉,照样工作

DaggerMainComponent.builder()                .build()                .inject(this)

再去看看Dagger生成的代码

public MainComponent build() {      if (mainModule == null) {        this.mainModule = new MainModule();      }      return new DaggerMainComponent(this);    }

原来,build方法会自动生成Module,所以可以不传入,拿什么时候才要传入Module呢?修改一下Module,在构造方法中传入参数

@Moduleclass MainModule(val activity: MainActivity) {    @Provides    @Singleton    fun provideString(): String = "123"}

编译之后再来看看生成的方法

public MainComponent build() {      if (mainModule == null) {        throw new IllegalStateException(MainModule.class.getCanonicalName() + " must be set");      }      return new DaggerMainComponent(this);    }

卧槽,变了…当Module有参数的时候就需要手动传入了,否则会抛异常。。