Dagger2的使用

这篇文章是对Dagger2使用的一个总结,参考了许多内容,会在下面把参考的资料列出来

什么是Dagger2

1.Dagger2是一个依赖注入框架。如果Class A 内部 有一个Class B,我们称作Class A依赖Class B

例如:

public class A{
  B  b
  public A(){
     b=new B();
   }
}

上述方法代码耦合度很高,如果B是一个父类,我们需要在A中用到不同的B类,是需要不断创建对象 B b1= new B1(),B b2=new B2();

2.依赖注入:是外界根据需要注入不同的对象。这样可以有效的降低耦合度。
像这种非自己主动初始化依赖,而通过外部来传入依赖的方式,我们就称为依赖注入。
参考资料:https://github.com/android-cn/blog/tree/master/java/dependency-injection

public class A{
  B b;
  public A(B b){
    this.b=b;
   }
 }

安卓应用在初始化对象的时候经常需要处理各种依赖关系。比如说网络访问中使用Retrofit,Gson,本地存储中使用shared preference。无一例外,我们都都需要在使用它们的地方进行实例对象构建,对象之间可能还存在着各种各样的依赖关系。依赖注入(Dependency Injection,简称DI)是用于削减计算机程序的耦合问题的一个法则。对象在被创建的时候,由一个调控系统内所有对象的外界实体将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。Dagger2 正是一个依赖注入框架,使用代码自动生成创建依赖关系需要的代码。减少很多模板化的代码,更易于测试,降低耦合,创建可复用可互换的模块。

*文/CameloeAnthony(简书作者)
原文链接:http://www.jianshu.com/p/01d3c014b0b1

一、配置Dagger2。

1.在项目的gradle中加入apt的依赖

Paste_Image.png

2.在module的gradle中加入dagger2需要依赖的库

Paste_Image.png

3.在module的gradle中加入插件支持

Paste_Image.png

4.如果已经都配置好了,那么需要makeproject一下。
在AndroidStudio中,点击一下红线标记的按扭


Paste_Image.png

二、Dagger2的使用

图片来自参考资料.png

1、既然是依赖注入,那么肯定有提供依赖的地方,在Dagger2中提供依赖的类被标注为Module,在Module中,具体提供对象的方法,被Provides注解标记。
2、从流程图中可以看出,Module中提供A对象给B和C。传递给B和C的工作由Component注解标记的接口来进行。
3、在B和C哪个对象要通过注入拿到对象则通过Inject注解进行标示。


图片来自参考资料

1.Inject注解

在Activity中,为LogUtils加上Inject注解,告诉编译器LogUtils需要通过注入的方式实例化。同样可以使用@inject注解标注构造方法,方法等。

  • 注意,被inject标注的不能是private修饰的对象。
  • interface是不能被构建的
  • 第三方的类不能被注解
  • 通过配置得到的对象,仍然必须通过配置得到(Builder模式构造的对象)
  • 如果使用@Inject标注了参数,如果没有通过Module提供依赖,会去查找是否有@Inject标注的构造方法,
    使用该构造方法提供依赖,如果该构造方法中也有参数,会去Module中查找是否提供了依赖。
Paste_Image.png

2.Module

Module是一个提供依赖对象的地方,需要使用@Module标注类,使用@Provide标注提供依赖的方法
编译器需要知道LogUtils的对象在哪里能够得到。这时需要一个提供对象的类,加上Module注解

  • 如果使用了@Scope注解为方法标注了使用的作用域,那么Component类上也需要有相应的作用域,否则编译报错。

  • 注意AppModuls的方法名是任意的,为了能更好的读懂代码一般都称作provider+对象名称。

Paste_Image.png

3.Component

1.有了提供的地方,需要一个桥梁让被标记为Inject的对象能够拿到自己对应的对象,因为Moduls类只是提供不负责传递。所以需要一个Component接口,被标记为Component的类就是这个媒介。
我们需要提供一个inject方法,并且参数一定要是对应的Activity,Fragment类,例如我在MainActivity中需要依赖注入,参数一定要为MainActivity,当然Component可以有多个inject方法,为不同的页面提供注入。

  • 全局的AppComponent只能含有一个带参的无返回值方法,用来给对应的地方实行注入。如:
  • 如果当前AppComponent被其他Component依赖了。其他Component提供依赖时,需要显示的提供依赖,即提返回对应依赖的无参方法。如:AppComponent
@Component(modules = {AppModule.class})
public interface AppComponent {   
void inject(ContainerActivity activity);
 Context getContext();
}
  • 注意除了使用dependencies对当前的component进行扩展,还可以使用subcomponent进行扩展
  • @dependencies 代表需要哪一个component提供依赖
  • @module 代表通过哪一个module提供依赖。
  • 如果你的module指定了作用域,那么component也要使用相同的注解标定作用域
  • component支持多个module 可以使用,号拼接,也可以使用下列写法。
@Module(includes={ModuleA.class,ModuleB.class,ModuleC.class})
public class FruitModule{ 
...
}
@Component(modules={FruitModule.class}) //添加多个Module
public interface FruitComponent{ 
...
}
Paste_Image.png

4.在Application中将Component桥梁实例化

如果你的配置都正确,并且makeproject了,编译器会自动为你的Component生成代码,名称是Dagger+你的Component名称。如果没有这个类,请查看在Gradle中配置是否正确,并且是否makeproject了。


Paste_Image.png

5.Activity拿到中介(桥梁Component),为对象注入

提供的中介当然就是我们在Application中实例化的Component了。

Paste_Image.png

三、Component的之间的依赖---SubComponent

除了使用@Component的dependience注解扩展当前component的支持的依赖,还可以通过SubComponent进行扩展,这有点像继承关系。并且父Component不用显示的抛出支持的依赖,只需添加一个返回子Component的方法

下面看一个来自于鸿洋Blog的图片

http://chuansong.me/n/400687651115
  • 使用@SubComponent标记子component
  • 使用SubComponent进行扩展,父component显示的抛出依赖,需要持有子component对象。
  • 通过父Component拿到子Component

注意两个地方
1.AppComponent 是根Component。
2.UserComponent 是子Component,UserComponent是通过appComponent得到。
这就是通过Component的相互依赖做到的。

1、UserComponent

使用@Subcomponent标注

@UserScope
@Subcomponent(modules = UserModule.class)
public interface UserComponent {
    AComponent plus(AModule aModule);
}
2、父Component

提供子Component。(返回值为子Component)

@Singleton
@Component(modules = AppModule.class)
public interface AppComponent {
    UserComponent plus(UserModule userModule);
}

三、@Name注解:区分不同对象的实例

该注解用来标识具体需要哪一个依赖。因为往往我们想要的对象不只有一种依赖方式。例如我们需要一个网络请求库,可能有提供缓存的,可能不需要缓存,那么这个时候我们在Moudle中就会提供两种依赖。具体选择哪个则需要通过name标识去取。

例如:
http://www.jianshu.com/writer#/notebooks/3267733/notes/4938210/preview
1.Module提供两种实例。

@Provides @Named("cached")@Singleton
OkHttpClient provideOkHttpClient(Cache cache) {
 OkHttpClient client = new OkHttpClient();
 client.setCache(cache); 
 return client;
}
 @Provides
 @Named("non_cached") 
 @Singleton
   OkHttpClient provideOkHttpClient() {
   OkHttpClient client = new OkHttpClient();
   return client; 
}

2.根据需求选取不同的实例

@Inject @Named("cached") OkHttpClient cache_client;
@Inject @Named("non_cached") OkHttpClient non_cache_client;

@Qualifier注解

当然Dagger2通过使用@Qualifier可以定制自己的Name形式注解。

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface UserNamed {
    String value() default "";
}

这和Dagger2提供的name的代码实现是一样的
下面是Dagger2提供的name

http://chuansong.me/n/400687651115

Scope注解:用于限定范围,指明Module可以像哪些对象提供依赖

1.定义自己Scope注解

@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface UserScope {

}

2.在Module中加入Scope注解,表示为哪些对象提供实例

鸿洋

3.在Component中加入Scope注解,表示在这个Component中,有权利从Module中拿到被Scope标注的对象

@UserScope
@Subcomponent(modules = UserModule.class)
public interface UserComponent {
    AComponent plus(AModule aModule);
    BComponent plus(BModule bModule);
    CComponent plus(CModule cModule);
}

参考资料

http://www.jianshu.com/p/01d3c014b0b1
http://chuansong.me/n/400687651115
http://blog.csdn.net/study_zhxu/article/details/52169090
http://android.jobbole.com/82705/
http://gold.xitu.io/entry/572232fc1532bc00624b5c8e
http://codethink.me/2015/08/06/dependency-injection-with-dagger-2/ 非常简洁清晰
http://ifarseer.github.io/2016/05/09/dagger2/

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,607评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,047评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,496评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,405评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,400评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,479评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,883评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,535评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,743评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,544评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,612评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,309评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,881评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,891评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,136评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,783评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,316评论 2 342

推荐阅读更多精彩内容

  • 部分内容参考自:[Android]使用Dagger 2依赖注入 - DI介绍(翻译)[Android]使用Dagg...
    AItsuki阅读 47,191评论 66 356
  • 本篇的内容不涉及Dagger2的源码,只是为了更好的使用. 想进一步了解的话可以阅读以下文章:dagger2让你爱...
    李庆雪阅读 988评论 0 3
  • 引入Dagger2 首先,我们需要将Dagger2的依赖写入我们的gradle中,具体配置如下 配置好之后就可以使...
    vonnie阅读 621评论 0 0
  • 本文的分析基于dagger2的2.7版本。 谷歌开发维护的Dagger2出来有很长时间了,目前在很多开源项目上也能...
    sososeen09阅读 13,584评论 31 108
  • 几个问题 看到Dagger2这个词的时候,相信很多人会有很多的疑问如下:Dagger2如何使用在例子中?Injec...
    codeHoward阅读 7,006评论 4 10