上篇简单介绍了一下依赖注入以及为什么我们要用依赖注入.
这篇主要介绍一下Dagger2的使用方法 并分析一下Dagger2的源码看看它是怎么实现的。
Dagger2用法还是蛮简单的,首先我们在Project根目录的gradle中添加apt依赖
//添加apt依赖
classpath'com.neenbedankt.gradle.plugins:android-apt:1.8'
在我们的Module app gradle里添加apt插件
//添加如下代码,应用apt插件
applyplugin:'com.neenbedankt.android-apt'
然后添加dagger2依赖以及注解依赖
compile'com.google.dagger:dagger:2.4'
apt'com.google.dagger:dagger-compiler:2.4'
//java注解
compile'org.glassfish:javax.annotation:10.0-b28'
好了喝杯咖啡等待我们gradle构建完毕吧. 所有依赖添加完后我们就可以使用了.
这里我们以一个MVP小例子举例,先介绍Dagger2的第一种用法
我们传统的MVP写法基本似这样子滴
这是我们创建的Activity v层:
public class MainActivity extends AppCompatActivity implements BaseView{
DemoPresenter mDemoPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
@Override
public voidsetXxx() {
}
}
我们创建一个Presenter:
public class DemoPresenter {
private BaseView mBaseView;
private DemoModule mDemoModule;
public DemoPresenter(BaseView baseView) {
mBaseView= baseView;
mDemoModule=newDemoModule();
}
public void getPerson() {
Person person =mDemoModule.getPerson();
if(person.mMsg.equals("1")) {
mBaseView.setXxx();
}
}
}
然后创建一个Module :
public class DemoModule {
publicPersongetPerson(){
Person p=null;
try{
Thread.sleep(1000);
p=newPerson("wubo","11");
}catch(InterruptedException e) {
e.printStackTrace();
}
return p;
}
}
好了这里我们Module 用Thread睡以下假装请求接口数据,好传统我们做法是在Activity的onCreate()中
DemoPresenter demoPresenter =new DemoPresenter(this);
然后在合适的地方调用
demoPresenter.getPerson();
现在有了Dagger2我们就不需要这样写了 我们可以在MainActivity presenter成员变量上加上@Inject注解
@Inject
DemoPresenter mDemoPresenter;
然后在presenter的构造上同样加上@Inject注解
public class DemoPresenter {
private BaseView mBaseView;
private DemoModule mDemoModule;
@Inject
public DemoPresenter(BaseView baseView) {
mDemoModule=newDemoModule();
}
public void getPerson() {
Person person =mDemoModule.getPerson();
if(person.mMsg.equals("1")) {
mBaseView.setXxx();
}
}
}
当我们在MainActivity用@Inject标注后Dagger会去标注的这个类的构造上寻找是否同样有@Inject标注如果有的话生成这个对象,当然如果构造上面你没有加@Inject那么是不会生成对象的请看官网文档说明
If your class has @Inject-annotated fields but no @Inject-annotated constructor, Dagger will inject those fields if requested, but will not create new instances. Add a no-argument constructor with the @Inject annotation to indicate that Dagger may create instances as well.
好了现在注解加了对象也生成了,可是怎么把生成对象添加到我们依赖的MainActivity中呢?这就要用到Component,Component是一个桥梁它连接我们的宿主和依赖
我们新创建一个Compnoent接口,注意Component是不需要我们自己去实现的我们只需要去定义接口和实现方法,具体实现细节Dagger会自动帮我们生成是不是灰常贴心。
@Component (modules = {Module.class})
public interface Compnoent {
void inject(MainActivity mainActivity);
}
(modules = {Module.class})
这里面我们要说明一下这个Component需要依赖哪些Module我们可以指定多个这里我们指定Module
贴上Module代码
@dagger.Module
public class Module {
private BaseView mBaseView;
public Module(BaseView baseView){
mBaseView = baseView;
}
@Provides
public BaseView getBaseView(){
return mBaseView;
}
}
这里我创建了一个Module构造里面参数传递宿主类也就是我们的MainActivity至于为什么这么继续看,下面定义了一个方法使用了
@Provides 咦这是什么东东,这个就是我们提供依赖对象的,比如
说我们可以new出来的对象可以用@Inject去注解构造,那么无法new
出来的对象怎么使用@Inject呢,比如
Interfaces can’t be constructed.
Third-party classes can’t be annotated.
Configurable objects must be configured!
所以Dagger给我们提供了Provides , Provides 是这样的在Dagger帮我们去创建依赖对象时,依赖对象中存在依赖对象或者构造中存在参数的时候,Dagger是没有这么智能也帮我们自动去生成的,这个时候Dagger会去@Module 类中 @Provides 依赖的方法找 哪个方法返回值复核依赖那么就赋值给这个依赖。
好了所以需要添加的代码我们添加完毕,现在我们在需要依赖的地方(比如MainActivity中的onCreate()中)调用
//方法一
DaggerCompnoent.builder().module(new Module(this)).build().inject(this);
就可以使用mDemoPresenter了
接下来我们介绍第二种依赖方式:
第二种方法我们不需要去使用@Inject注解了,其实我个人认为第二种方法不是依赖注入了因为这种方式生成的对象并不是Dagger注入进去的而是我们自己生成的只不过不是在宿主中生成了,可能有点绕我们继续看下去就会清除了。
第二种方式我们把所有使用@Inject全部去掉, 同样的还需要创建Module和Compnoent,Module创建的代码跟方式跟上面的一模一样,Compnoent 需要我们改一改
//之前我们是这样创建的
@Component (modules = {Module.class})
public interface Compnoent {
void inject(MainActivity mainActivity);
}
//现在我们改成这样不需要传递宿主类了
@Component (modules = {Module.class})
public interface Compnoent {
DemoPresenter getPresenter();
}
我们看到上面我们把代码改成了返回一个DemoPresenter 的方法,为什么要这么做呢,因为Dagger会帮我们去实现Component 注解的所有方法,当Dagger实现getPresenter()方法需要返回一个DemoPresenter 时候它怎么办呢?我们前面说了所有依赖中需要的依赖Dagger都会去Module中的Provide去找,所以我们前面的Module中同样需要改动的,我们添加一个
拿到DemoPresenter 的方法,你不添加Dagger怎么找的到呢,
@dagger.Module
public class Module {
private BaseView mBaseView;
public Module(BaseView baseView){
mBaseView = baseView;
}
@Provide
public DemoPresenter getPresenter(){
return new DemoPresenter (mBaseView );
}
}
现在我们可以在MainActivity中这么调
//方法二
DemoPresenter mDemoPresenter =DaggerCompnoent.builder().module(new Module(this)).build().getPresenter();
这样我们就直接生成了一个DemoPresenter 对象
我们总结一下二种方式的区别
方法一: 通过在宿主类(MainActivity)中的依赖上添加@Inject,然后在依赖类的构造上@Inject ,Dagger自动生成依赖类的对象,然后创建一个@Module依赖的Module类,通过Module的构造方法传入宿主类,声明成员变量,然后添加一个@Provide依赖的方法,方法返回宿主对象也就是我们声明的成员变量.最后我们创建一个@Component依赖的Component接口Component 要申明我们要依赖的Module (modules = {Module.class})
Component接口中申明一个方法,方法中参数传递我们的宿主对象, void inject(MainActivity mainActivity);
然后在宿主类中调用
DaggerCompnoent.builder().module(new Module(this)).build().inject(this);
方法二:
创建一个@Module依赖的Module类,通过Module的构造方法传入宿主类,声明成员变量,然后添加一个@Provide依赖的方法,方法返回宿主对象也就是我们声明的成员变量,再多添加一个@Provide
Dagger还提供了@Signal
@Provide
public DemoPresenter getPresenter(){
return new DemoPresenter (mBaseView );
}
然后Component接口改成这样
@Component (modules = {Module.class})
public interface Compnoent {
DemoPresenter getPresenter();
}
宿主类中我们这样直接生成依赖对象
//方法二
DemoPresenter mDemoPresenter =DaggerCompnoent.builder().module(new Module(this)).build().getPresenter();
二种方式已经介绍完毕,艾玛,写的累死宝宝了,好了,使用方法介绍完毕,现在我们解开Dagger神秘的面纱看看Dagger是怎么自动生成代码的是怎么把依赖注入到宿主类中的,敬请期待你所看到最轻松的Dagger2讲解(源码分析)