什么是dagger2
Dagger是为Android和Java平台提供的一个完全静态的,在编译时进行依赖注入的框架,原来是由Square公司维护,现在由Google维护。一句话,dagger2其实就是一套依赖注入框架。那么什么是依赖注入呢?
具体含义是:当某个角色(可能是一个Java实例,调用者)需要另一个角色(另一个Java实例,被调用者)的协助时,在 传统的程序设计过程中,通常由调用者来创建被调用者的实例。但在dagger2里,创建被调用者的工作不再由调用者来完成,而是由dagger2来完成,然后注入调用者,因此也称为依赖注入。
为什么需要dagger2
说实话,刚接触dagger2的时候我也是一脸懵逼,这个东西这么繁琐,为什么要用它呢?这个问题其实就是为何我们需要依赖注入。有本书上这样写道:依赖注入不是目的,它是一系列工具和手段,最终的目的是帮助我们开发出松散耦合、可维护、可测试的代码和程序。可想而知,其最终目的是实现解耦。何为解耦?怎么解耦?举个例子说明一下:
前面我们讲到MVP架构,我们的Presenter层构造函数可能需要一些参数:访问服务端的AbsService实例,做网络请求线程切换的SchedulerProvider ,如下,
public class TestPresenter extends BasePresenter<TestView> {
AbsService mAbsService;
SchedulerProvider mSchedulerProvider;
public TestPresenter(AbsService absService,SchedulerProvider schedulerProvider) {
this.mAbsService=absService;
this.mSchedulerProvider=schedulerProvider;
}
}
那么我们在实例化这个Presenter的时候就需要这样做:
AbsService mAbsService=AbsService.getInstance();
SchedulerProvider schedulerProvider=SchedulerProvider.DEFAULT;
TestPresenter testPresenter=new TestPresenter(mAbsService,schedulerProvider);
需要把TestPresenter需要的参数一个个的实例化,然后作为参数传给它。试想一下,如果我们的AbsService和SchedulerProvider 还需要很多参数,或者TestPresenter需要3个乃至更多的参数,那我们实例化一个TestPresenter要做的操作是不是太多了,这样实在是太夸张了,我们只是需要一个TestPresenter实例而已,就必须知道TestPresenter的Dependency是什么,TestPresenter的Dependency的Dependency是什么。。。首先这样做操作很是繁琐,其次,这样做,导致代码耦合程度非常高,我们改变其中一环的时候,就要做大量的代码改动。
然而,如果我们使用dagger2,这些问题就可以迎刃而解了。dagger2用一个类似依赖工厂的东西,将所需的依赖统一管理起来,所有需要用到依赖的类都可以到这里寻找相应的依赖,并且dagger2会自动搜索这个类所用到的依赖的依赖,系统会自动识别这个依赖关系。
Dagger2的基本使用方法
Dagger2主要由2个部分组成:首先我们需要一个产生依赖的工厂Module,然后我们需要一个管理这些Module的管理员Component。
Module的实现(接前面的例子):
@Module
public class AppModule {
@Provides
public SchedulerProvider provideSchedulerProvider() {
return SchedulerProvider.DEFAULT;
}
@Provides
public AbsService provideApi() {
return AbsService.getInstance();
}
@Provides
public AbsService.AbsApi provideAbsApi() {
return AbsService.getService();
}
@Provides
public TestPresenter providePresenter(AbsService absService,SchedulerProvider schedulerProvider) {
return new TestPresenter(absService,schedulerProvider);
}
}
在上面的Module类的中,我们用@Module注解标注了这个类,告诉dagger2这个类是提供依赖的Module,下面很多个用@Provides注解标注的方法则是告诉dagger2这个方法用来提供依赖。如果需要提供单例的依赖则需要在前面,加上@Singleton注解。这个时候,可能有人会有疑问了,多层的依赖dagger是怎么找的?dagger2寻找依赖的规则如下:
步骤1:首先查找@Module标注的类中是否存在提供依赖的方法。
步骤2:若存在提供依赖的方法,查看该方法是否存在参数。
a:若存在参数,则按从步骤1开始依次初始化每个参数;
b:若不存在,则直接初始化该类实例,完成一次依赖注入。
步骤3:若不存在提供依赖的方法,则查找@Inject标注的构造函数,看构造函数是否存在参数。
a:若存在参数,则从步骤1开始依次初始化每一个参数
b:若不存在,则直接初始化该类实例,完成一次依赖注入。
通过这样一个操作,dagger2就能直接自动的寻找所需的依赖了。
Component的实现:
@Component(modules = {AppModule.class})
public interface AppComponent {
TestPresenter testPresenter();
}
或是
@Component(
modules = AppModule.class
)
public interface AppComponent {
TestActivityFragment2 inject(TestActivityFragment2 activity);
}
Component需要用 @Component修饰一下,来标注这是一个dagger2的Component,而不是一个普通的interface,用modules = AppModule.class来告诉dagger2要从哪个Module中去找依赖,注意如果有多个Module,可以和第一种方法一样写成数组的形式。
在Component中的方法是我们需要使用依赖的时候使用的,比如第一种,就比较直观,我们需要TestPresenter 这个实例,直接定义这个方法,dagger2就会自动生成一个Dagger+Component名字(如DaggerAppComponent )这样一个方法,这个方法就从AppComponent管理的AppModule中寻找依赖,返回一个Presenter的实例。
然后在需要调用实例的时候只需要像下面这样做就可以完成实例化了:
public class TestActivityFragment2 extends Fragment {
private TestPresenter mTestPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
AppComponent appComponent = DaggerAppComponent.builder().appModule(new AppModule(this)).build();
mTestPresenter= appComponent.testPresenter();
}
}
对于第二种方式,我们需要这样调用:
public class TestActivityFragment2 extends Fragment {
@Inject
TestPresenter mTestPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
AppComponent appComponent = DaggerAppComponent.builder().appModule(new AppModule(this)).build();
appComponent.inject(this);
}
}
DaggerAppComponent实现这个方法的方式是,去TestActivityFragment2 里面所有被 @Inject修饰的变量,然后调用 AppModule相应的Provider方法对相应类型提供依赖。对于这两种方法,一般来说我会选择第二种,写起来比较简便。