Dagger2学习篇——简单使用
Dagger2学习篇——注入原理
Dagger2学习篇——2.11版本后代码简化及原理分析
依赖注入
依赖注入:
就是目标类中所依赖的其他的类的初始化过程,不是通过手动编码的方式创建,而是通过技术手段可以把其他的类的已经初始化好的实例自动注入到目标类中。
实例:
- Class A中用到了Class B的对象b,一般情况下,需要在A的代码中显式的new一个B的对象。采用依赖注入技术之后,A的代码只需要定义一个私有的B对象,不需要直接new来获得这个对象,而是通过相关的容器控制程序来将B对象在外部new出来并注入到A类里的引用中。而具体获取的方法、对象被获取时的状态由配置文件(如XML)来指定。
- 在mvp中,presenter层会持有view和model层的依赖,依赖注入主要用于解耦,通过依赖注入创建对象,不再使用new来创建对象。
依赖注入的几种方式:
通过接口注入
interface ClassBInterface {
void setB(ClassB b);
}
public class ClassA implements ClassBInterface {
ClassB classB;
@override
void setB(ClassB b) {
classB = b;
}
}
通过set方法注入
public class ClassA {
ClassB classB;
public void setClassB(ClassB b) {
classB = b;
}
}
通过构造方法注入
public class ClassA {
ClassB classB;
public void ClassA(ClassB b) {
classB = b;
}
}
通过Java注解
public class ClassA {
//此时并不会完成注入,还需要依赖注入框架的支持,如RoboGuice,Dagger2
@inject ClassB classB;
...
public ClassA() {}
}
Dagger2注解用法
注解 | 用法 |
@Inject | 在需要依赖注入的地方使用这个注解。(通过它告诉Dagger:这个构造方法、成员变量或者函数方法需要依赖注入,Dagger就会构造一个这个类的实例并满足他们的依赖。) |
@Module | 带有此注解的类,用来提供依赖,里面定义一些用@Provides注解的以provide开头的方法,这些方法就是所提供的依赖,Dagger2会在该类中寻找实例化某个类所需要的依赖。 |
@Provide | 在modules类中定义的方法会使用这个注解,以此来告诉Dagger我们想要构造对象并提供这些依赖。 |
@Singleton | 当前提供的对象将是单例模式,一般配合@Provides一起出现。 |
@Component | 用于接口,这个接口被Dagger2用于生成用于模块注入的代码。用来将@Inject和@Module联系起来的桥梁,从@Module中获取依赖并将依赖注入给@Inject。 |
@Scope | Dagger2可以通过自定义注解限定注解作用域。 |
Dagger2的使用
具体引入和依赖的方法根据不同版本有不同的方式(参考Dagger2 github)
基于MVP的实例:在mvp中,最常见的一种依赖关系,就是Activity持有presenter的引用,并在Activity中实例化这个presenter,即Activity依赖presenter,presenter又需要依赖View接口,从而更新UI。
未使用Dagger2的情况:
// Activity代码
public class MainActivity extends AppCompatActivity implements MainContract.View {
private MainPresenter mainPresenter; // 方法1
...
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 实例化presenter 将view传递给presenter
mainPresenter = new MainPresenter(this); // 方法1
// 调用Presenter方法加载数据
mainPresenter.loadData();
...
}
}
// Presenter代码
public class MainPresenter {
// MainContract是个接口,View是他的内部接口,这里看作View接口即可
private MainContract.View mView;
MainPresenter(MainContract.View view) { // 方法1
mView = view;
}
public void loadData() {
// 调用model层方法,加载数据
...
// 回调方法成功时
mView.updateUI();
}
}
// Contact代码
public class MainContract {
interface View {
void updateUI();
}
}
使用了Dagger2的情况:
// Activity代码
public class MainActivity extends AppCompatActivity implements MainContract.View {
@Inject
MainPresenter mainPresenter; // 方法2
...
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerMainComponent.builder() // 方法2
.mainModule(new MainModule(this))
.build()
.inject(this);
// 调用Presenter方法加载数据
mainPresenter.loadData();
...
}
}
// Presenter代码
public class MainPresenter {
// MainContract是个接口,View是他的内部接口,这里看作View接口即可
private MainContract.View mView;
@Inject
MainPresenter(MainContract.View view) { // 方法2
mView = view;
}
public void loadData() {
// 调用model层方法,加载数据
...
// 回调方法成功时
mView.updateUI();
}
}
// Contract代码
public class MainContract {
interface View {
void updateUI();
}
}
// MainModule 代码
@Module
public class MainModule {
private final MainContract.View mView;
public MainModule(MainContract.View view) {
mView = view;
}
@Provides
MainContract.View provideMainView() {
return mView;
}
}
// MainComponent 代码
@Component(modules = MainModule.class)
public interface MainComponent {
void inject(MainActivity activity);
}
MainActivity里的MainPresenter加了一个注解@Inject,MainPresenter的构造函数上也同样加了@Inject注解,这样MainActivity里的mainPresenter与MainPresenter的构造函数建立了联系,此时会自动初始化MainPresenter这个类,从而完成依赖注入。这种联系不会凭空建立,需要Component作为桥梁。
Component是一个接口或者抽象类,用@Component注解标注,在这个接口中定义一个inject()方法,参数是Mainactivity。然后rebuild一下项目,会生成一个以Dagger为前缀的Component类,这里是DaggerMainComponent,然后在MainActivity里完成下面代码:
DaggerMainComponent.builder()
.mainModule(new MainModule(this))
.build()
.inject(this);
MainModlue是一个注解类,用@Module注解标注,主要用来提供依赖。之所以有Module类主要是为了提供那些没有构造函数的类的依赖,这些类无法用@Inject标注,比如第三方类库,系统类,以及上面示例的View接口。
MainModule类里声明了MainContract.View成员属性,在构造方法里将外界传进来的view赋值给mView,并通过一个@Provides标注的以provide开头的方法,将这个view返回,这个以provide开头的方法就是提供依赖的,我们可以创建多个方法来提供不同的依赖。Module要发挥作用,还是要依靠于Component类,一个Component类可以包含多个Module类,用来提供依赖。
通过new MainModule(this) 将view传递到MainModule里,然后MainModule里的provideMainView() 方法返回这个View,当去实例化MainPresenter时,发现构造函数有个参数,此时会在Module里查找提供这个依赖的方法,将该View传递进去,这样就完成了presenter里View的注入。
注:文章部分参考自https://www.jianshu.com/p/cc2acebf013d,由于不清楚真正的出处,这里引用了一篇。