dagger2作为google出的依赖注入框架,在编译时生成依赖注入代码,较square的dagger在运行期反射获取注解内容在运行效率上有了较大的提升。dagger2相对而言学习成本较高,但在解耦较高尤其与mvp的结合使用,还是给项目带来很大的好处。相信有很多的开发者都蠢蠢欲动。关于dagger2原理介绍的文章也有很多,本文主要介绍一下在使用过程中比较常见的一个错误,希望能够帮助大家从错误中更深刻掌握dagger2的一些原理。
一、先看错误:
com.example.zengxianghui900.dagger2application.compoment/Users/zengxianghui900/Downloads/Dagger2Application/app/src/main/java/com/example/zengxianghui900/dagger2application/compoment/MainActivityCompoment.java:14:
Error:(14, 10) 错误: com.example.zengxianghui900.dagger2application.presenter.Register cannot be provided without an @Inject constructor or from an @Provides-annotated method.com.example.zengxianghui900.dagger2application.MainActivity.mPresenter[injected field of type:com.example.zengxianghui900.dagger2application.presenter.MainActivityPresenter mPresenter]com.example.zengxianghui900.dagger2application.module.MainActivityModule.provideMainActivityPresenter(com.example.zengxianghui900.dagger2application.presenter.Register register)[parameter: com.example.zengxianghui900.dagger2application.presenter.Register register]
在它上面还有一个错误(如下):
Error:(9, 64) 错误: 找不到符号
符号: 类 DaggerMainActivityCompoment
位置: 程序包 com.example.zengxianghui900.dagger2application.compoment
二、分析错误
主要看这句:Register cannot be provided without an @Inject constructor or from an @Provides-annotated method,意思是说Register这个类对象不能通过带@Inject的构造函数或带@provieds 注解的方法中获得,所以会报错。
为什么呢?
看报错指向,其指向的是:MainActivityCompoment
/**
* Created by zengxianghui900 on 17/4/24.
* MainActivityCompoment
*/
@Component(modules = MainActivityModule.class)
public interface MainActivityCompoment {
void injectMainActivity(MainActivity mainActivity); //指向这句报错
}
其实际指向的是MainActivityModule
/** * Created by zengxianghui900 on 17/4/24. * MainActivityModule */ @Module public class MainActivityModule { @Provides MainActivityPresenter provideMainActivityPresenter(Register register) { //实际指向这句,没法获得参数register对象 return new MainActivityPresenter(register); } }
再看一下Regist类和MainActivityPresenter里面的内容,很简单:
/**
* Created by zengxianghui900 on 17/4/25.
*
*/
public class Register {
private static final String TAG ="Register";
public void toast() {
Log.e(TAG, "toast: 注册成功了。。。");
}
}
/**
* Created by zengxianghui900 on 17/4/24.
*/
public class MainActivityPresenter {
private Register mRegister;
public MainActivityPresenter(Register register) {
this.mRegister = register;
}
//定义一个方法弹一个土司
public void showToast() {
mRegister.toast();
}
}
三、解决错误
既然都知道错误产生的原因了,那接下来看一下怎么解决,有两种方案:
第一种方案:
在MainActivityModule中通过@Provides提供Register实例对象,如下:
/**
* Created by zengxianghui900 on 17/4/24.
* MainActivityModule
*/
@Module
public class MainActivityModule {
//添加提供Register实例对象的方法
@Provides
Register provideRegister() {
return new Register();
}
@Provides
MainActivityPresenter provideMainActivityPresenter(Register register) {
return new MainActivityPresenter(register);
}
}
第二种方案:
在Register类中能过@Inject注解其构造函数,如下:
/**
* Created by zengxianghui900 on 17/4/25.
*
*/
public class Register {
private static final String TAG ="Register";
//用Inject标注构造函数
@Inject
public Register(){
}
public void toast() {
Log.e(TAG, "toast: 注册成功了。。。");
}
}
以下任何一种方案都能解决这个问题,那么原理呢?
逻辑如下:
1. provideMainActivityPresenter方法会先去判断该module中是否有提供Register实例对象的方法,有则成功返回结束。
2. 如果没有,会再去Register类中查找是否有带@Inject标记的构造方法,如果有则成功返回结束。
3.如果也没有,那么就会报这个错误了。