前言
Dagger2是依赖注入的框架,网上有很多关于dagger的使用方法。好处想必大家都能知道就是解耦。 那解谁和谁耦合呢?就是对象实例化和使用宿主的耦合。
我看了网上有很多使用的说,说Dagger多好,比原有多写了一大堆代码,然后说框架好解耦。说实话我看了他们的代码没觉得有多好, 为了达到某一个目的,饶了一大圈, 我不愿意。我写代码喜欢简洁优雅,用框架无非就是用少量的代码实现更好的结构。如果非需要,写一大堆让人眼花缭乱的代码证明自己有多diao,好吧,你赢了。
废话不扯了,今天主要讲讲我对Dagger2实际使用的理解。
实际使用
首先简单说说Dagger2,比较懒,用网上一张图标识( 如下图 )
上图比较清晰的展示了Dagger2的结构。我来人物角色介绍一下:
Module: 实例化工厂类. 类似于医院的药房,有中药房,西药房等,专门负责提供药品的。
Component: 注入器。类似于护士,护士帮病人拿药,去哪拿呢,去上面的药房。
Container:宿主,被注入的对象。 类似于病人,你需要要什么药?写个清单( 就在你的变量上面用 @Injectde标记一下) 叫上面的护士帮你拿药。
问题来了,病人( Container )请护士( Component )拿药,他希望找一个还是多个呢?
有人说,得分开,西药的西药房护士拿,中药让中药房护士拿.... 累不累,病人管你什么类型的药,那是你医院为了管理分的类别。就找一个护士,你具体怎么拿药,流程多复杂,那是你的事情。
OK,Container中只需要一个Component来注入。
讲到这,我得画张图 ( 当然没有网上的大牛画的好看,我是画板画的 ),上面的图只是Dagger的结构,实际使用的有点出入:
在实际使用中,病人( Container )不止一个,那需要多少个护士( Component )呢?有人说1个病人一个护士,哪个医院那么好,提供1对1的VIP服务。
我们写App,现在就是医院领导,你希望聘用几个护士呢? 我希望是越少越好,如果一个能干活的最好,写那么多干嘛,浪费我手敲代码。
问题来了,需要几个护士( Component )呢?
我也不知道几个,作为app的构造者,不能这样。那怎么办,咱们从下往上看,看看需要几个护士干活不就行了。
那么多病人( Contaniner )需要要很多种药( 需要注入的对象 ),我们来给这些药分类下。需要注入的对象我们根据实例化需要参数的不同分不同类。例如
NetworkHelper(Context context)
ToastUtils(Context context)
DBUtils(参数1 a , 参数2 b)
XXXDao(参数1 a , 参数2 b)
为什么要这么分呢,因为对象实例化需要的参数是通过Module工厂类的构造方法传进去的。所以需要Context参数的,就放在 ModuleA(Context ctx) 这个工厂类里面产生。
有人说我不懂哦? 就是例如 有些药需要提供医生的处方才能取的,我把他们放在一个药房,有些需要实名认证的,我也放在一个药房。有些直接付钱就能取药的,例如无参的对象。
还好安卓简单一些,一般需要注入的对象,无非就是分2种,需要上下文对象的 和 无参的。当然我一般会定义4个Module, 前2个是搭框架的时候,需要的注入常规的,后2个是实际业务需要的注入的。其实还是2个,只不过把共用的提出来。
有人说,我注入的对象例如 DialogUtil(Context cxt , String title),每次使用String都传的不一样,怎么办? 大哥不带这么玩的,title属于具体到某个业务场景了,你就不能DialogUtil(Context cxt) , 然后 DialogUtil.set(String title)
结论有了,Module数量 >= 2个,安卓一般就2个,ModuleA(Context ctx) 和 ModuleB( )。
跑题是吧,问题是护士需要几个?
那我们再来问一次,需要几个护士( Component )呢?
理论上其实一个就够了。
但是Dagger有个注解@Scope @Singleton,提到了生命周期。哦?Dagger作为医院,他其实是药品的储存的容器,他还有一个功能,就是管理所有注入变量的生命周期。这个好理解,例如酒精 消毒的,你每次去医院消毒不会买瓶酒精吧,这个是共用的全局变量。 有些药是一次性。
那我们的App,注入实例有哪几种生命周期呢,我这分为4个 ==> 1. @Application 全局的 2. 和宿主生命轨迹一样 3. 注入到宿主后,用到了就产生,用不到就不会实例化 4. 一次性的,每次都是新的。
作为医院的领导,聘用护士当然也分了,有的签的是永久制合同,有的签的是临时合同,还有的是实习生。
为什么要这么分呢,注入实例的生命周期是跟护士是有关的。如果你用@Scope标识工厂类产生实例A的方法,那就说明这个实例A的生命周期和他那个Component生命周期一样。全局的护士当然拿的药品A就是全局的,咱们下一篇可以看看Dagger帮我们自动生成的Component的实现类。
那我们看看上面的4中生命周期的注入对象怎么实现呢?
1. @Application 全局的对象 我们就不要用什么单例了, 用全局的Component就可以了。
那全局的Component怎么实现呢?在Application只初始化一次就行了
2. 和宿主生命轨迹一样 就是正常的 @Inject
3. 注入到宿主后,用到了就产生,用不到就不会实例化 这个在注入的时候
用Lazy<需要注入的对象>
4. 一次性的,每次都是新的。 用 Provider<需要注入的对象>
1个Component能显示这四个么? 答案是肯定的,上代码
@Component(modules={ModuleA.class,ModuleB.class,ModuleC.class ..... })
@Application
public interface XXXComponent {
void injectAAA(AAA aaa);
void injectBBB(BBB bbb);
}
结论有了, Component数量 >= 1,我一般写1个
使用总结
综上所述,咱们在实际App开发中,Dagger的框架大致是如下:
在谈谈耦合
咱们在Container里使用Compontent的时候,一般代码是如下:
MineComponent component=DaggerMineComponent.builder().appModule(appModule).build();
component.injectXXX(this);
当你的Module不是无参的构造方法,Dagger框架需要你提供Module的实例。
呵呵,是不是感觉白忙活了是吧,刚减少对具体实例的依赖,现在对工厂类产生依赖。
我的做法是Component在Application里面生成。 然后用个静态方法,在具体宿主中取Component。
public class ComponentInject {
..........
public static MineComponent getComponent() {
return inject.mineComponent;
}
}
public XActivity extend AppCompatActivity {
....
onCreate(Bundle savedInstanceState) {
ComponentInject.getComponent().injectHome(this);
}
}
先写这,下一篇咱们看看Dagger生成的代码。