Dagger2 使用正确姿势。

来源:互联网 发布:集金号软件下载 编辑:程序博客网 时间:2024/06/10 05:12

Dagger2 使用正确姿势。

上一篇文章《[Dagger2 这次入门就不用放弃了](http://blog.csdn.net/u012943767/article/details/51897247》中介绍了Dagger2的一些显浅的使用方式,我觉得是非常适合入门Dagger2的傻瓜式讲解,后来发现有些内容讲的不够仔细,有些细节没有详细解释清楚。参考了以下三篇文章后,对之前的内容进行一些补充。

  • Android:dagger2让你爱不释手-基础依赖注入框架篇
  • Android:dagger2让你爱不释手-重点概念讲解、融合篇
  • Android:dagger2让你爱不释手-终结篇

以上这三篇文章对于Dagger2的思路理得很清晰,并且对于Dagger2做出了一个抽象的概念讲解,本文的一些内容也是摘自以上文章。

没有看过《Dagger2 这次入门就不用放弃了》可能不利于阅读

本文的内容:

本篇的内容同样不涉及到Dagger2的内部原理,只是对上一篇文章做了一些知识的补充,从而能够更好的使用Dagger2

  • 理清思路,Dagger2的两种提供注入实例的方式
  • 为什么ActivityComponent要提供一个inject方法。
  • Scope的使用,如何实现单例?
  • Qualifier限定符的作用以及使用。
理清思路,Dagger2的两种提供注入实例的方式。

之前说的是提供注入实例的方式是通过编写Moudle,并且提供一些provideXXX()的方法,然后通过Component把这些对象进行注入。
其实在Dagger2中还有一种方式实现对象的注入,这种方式比较简单。假设我们需要注入一个A类的对象,我们只需要在A类的构造函数中添加@Inject注解即可,然后在Component中直接提供一个方法获取A的实例就行了。代码如下:

public class A{    @Inject    public A(){    }}//在  XXXComponent 中A getA();

然后在我们需要注入A对象的地方(Activity),使用Component调用getA()方法即可获得这个A对象。

说到这里,可能也会有些疑问,这里的A类是一个简单的对象,假如A需要在构造函数传入参数怎么办?其实原理和上一篇文章说的差不多,这些参数会根据依赖的Component或者当前Componentmodule中提供的provideXXX()方法来获取。

这里的Dagger2总共就有这两种方式提供依赖的注入。事实上,经过测试,Dagger2在遇到@Inject修饰的成员变量的时候,会先查找Component中是否有提供对象,找不到的情况下,才会去找包含有@Inject的构造函数。

整个Dagger2的依赖注入的过程如下:

步骤1:查找Module中是否存在创建该类的方法。步骤2:若存在创建类方法,查看该方法是否存在参数    步骤2.1:若存在参数,则按从**步骤1**开始依次初始化每个参数    步骤2.2:若不存在参数,则直接初始化该类实例,一次依赖注入到此结束步骤3:若不存在创建类方法,则查找Inject注解的构造函数,           看构造函数是否存在参数    步骤3.1:若存在参数,则从**步骤1**开始依次初始化每个参数    步骤3.2:若不存在参数,则直接初始化该类实例,一次依赖注入到此结束
为什么ActivityComponent要提供一个inject方法

首先经过我的测试,当我在DaggerActivity中对对某些需要注入的成员添加@Inject注解的时候,Dagger2就会生成一个DaggerActivity_MembersInjector的东西,这个是对成员变量进行注入的关键类,涉及到一些比较深入的内容,我们这里先不要深入探讨这里的运行机制。我们只需要知道当我们需要注入一些成员变量的时候,我们需要在ActivityComponent中提供一个方法:

void inject(DaggerActivity daggerActivity);

并且在初始化的时候调用这个方法,才能成功注入。至于这个方法inject是官方推荐的名称,我们可以不用这个,但是使用inject的话比较好理解吧。值得注意的一点是,这个方法的参数一定要准确,比如DaggerActivity需要注入,我们这里就需要些DaggerActivity,不能写成BaseActvity或者Activity,否则会注入失败。因为内部的原理是要对这个参数进行注入的,很显然在DaggerActivity中需要注入的内容在BaseActivity或者Activity中并不存在。

Scope的使用,如何实现单例?

这个迷之Scope也是有点难以理解,我们在哪里使用到了Scope呢。在我们的AppComponent中添加了一个注解为@Singleton@Singleton就是一个Scope,据说可以实现单例哟。。。难道这样就实现了单例模式?我刚刚开始是这样理解的。直到仔细的看了几遍这篇文章我才知道并不是这样的。

事实上@Sinleton中并没有创建单例的能力,那么AppComponent中提供的依赖注入是如何实现单例的呢。其实这个原理很贱单。

首先Module提供了创建实例的方法,接着AppComponent中对Module进行管理,最后AppComponent在自定义Applicaiton中被实例化了一次

这个实例化了一次是最重要的呀。仅仅被实例化了一次,那不就是单例么。就是这么简单呀。

可能有些童靴当时就不乐意了,那既然这样都已经实现了单例,那么这个@Singltop还要来何用?不是多此一举吗。

其实@Singletop还有有一些作用的,首先一方面能让你直面的了解到这是一个单例,其次这个@Singletop能够更好的管理ModlueComponent之间的关系。

Dagger2需要保证ComponentModule是匹配的,就需要用到这个注解。

为什么这样说,看过上一篇文章的人就会知道,我定义了一个ActivityScope,我之前的解释是说ActivityScope是为了对应Activity的生命周期(当时就很不理解,难道这个Scope真的这么有魔性,声明一个ActivityScope就能让提供的注入对象和Activity生命周期一致),很显然,这是错误的。为什么需要这个Scope呢?原因是因为我在AppComponent中是有@Singletop的,ActivityComponent中依赖了AppComponent,所以我们需要使用一个Scope来匹配他们之间的关系,不然就会在编译期间报错。并不是说ActivityScope能让实例和Activity生命周期一致。和Activity生命周期一致是因为ActivityComponent是在Activity中生成实例的。(具体Dagger2内部是如何保障这个的,并没有深入研究过)。

Qualifier 限定符的作用以及使用。

这也是一个很强大的注解,首先为什么需要用这么一个东西呢,之前说道过,在Module中的provide方法实际上是根据返回值来进行识别的。但是假设我需要根据不同的需求传入不同的构造参数的时候,如何区分呢?比如:一个Presenter,可能他有两个构造函数,分别对应不同的需求,这种情况下,provide方法的返回值都是Presenter,那么就需要使用Qualifier。具体怎么使用呢。

首先声明一个注解用@Qualifier修饰,然后在需要区别的地方添加就行了,下面是一个实例代码:

@Modulepublic class AppModule {    private final App app;    public AppModule(App app) {        this.app = app;    }    @Provides    @Singleton    @ForApplication    Context provideAppContext() {        return app;    }    @Provides    @Singleton    Prefser providePrefser(@ForApplication Context context) {        return new Prefser(context);    }    @Provides    @Singleton    AccountManager provideAccountManager(@ForApplication Context context) {        return AccountManager.get(context);    }

首先在provide中添加一个注解@ForApplicition,接着在需要使用这个Context的地方再次标示即可。这样假设有其他一些提供了ActivityContext的地方和这里发生冲突的时候,Dagger2也能准确找到这个ApplicaitonContext

总结

这里对Dagger的总体使用方式进行了一些补充,还有没有从源码的角度来理解Dagger2,下篇文章会结合Dagger2生成的代码进行讨论,只有认识了这个运行机制,我们才能运用得得心应手。

0 1
原创粉丝点击