dagger2框架解析

Dagger2定义

Dagger2 是一个Android依赖注入框架,由谷歌开发,最早的版本Dagger1 由Square公司开发。依赖注入框架主要用于模块间解耦,提高代码的健壮性和可维护性。Dagger 这个库的取名不仅仅来自它的本意“匕首”,同时也暗示了它的原理。Jake Wharton 在对 Dagger 的介绍中指出,Dagger 即 DAG-er,这里的 DAG 即数据结构中的 DAG——有向无环图(Directed Acyclic Graph)。也就是说,Dagger 是一个基于有向无环图结构的依赖注入库,因此Dagger的使用过程中不能出现循环依赖。


那什么是依赖呢?如果在 Class A 中,有 Class B 的实例,则称 Class A 对 Class B 有一个依赖。例如下面类 Human 中用到一个 Father 对象,我们就说类 Human 对类 Father 有一个依赖。


那什么又是依赖注入呢,依赖注入就是非自己主动初始化依赖,而通过外部来传入依赖的方式,简单来说就是不使用 new 来创建依赖对象。使用 Dagger2 创建依赖对象,我们就不用手动初始化了。个人认为 Dagger2 和 MVP 架构是比较不错的搭配,Activity 依赖的 Presenter 可以使用该DI框架直接生成,实现解耦,简单的使用方式如下:


dagger2到底有哪些好处?
1.增加开发效率、省去重复的简单体力劳动

首先new一个实例的过程是一个重复的简单体力劳动,dagger2完全可以把new一个实例的工作做了,因此我们把主要精力集中在关键业务上、同时也能增加开发效率上。

省去写单例的方法,并且也不需要担心自己写的单例方法是否线程安全,自己写的单例是懒汉模式还是饿汉模式。因为dagger2都可以把这些工作做了。

2.更好的管理类实例

每个app中的ApplicationComponent管理整个app的全局类实例,所有的全局类实例都统一交给ApplicationComponent管理,并且它们的生命周期与app的生命周期一样。

每个页面对应自己的Component,页面Component管理着自己页面所依赖的所有类实例。

因为Component,Module,整个app的类实例结构变的很清晰。

3.解耦

假如不用dagger2的话,一个类的new代码是非常可能充斥在app的多个类中的,假如该类的构造函数发生变化,那这些涉及到的类都得进行修改。设计模式中提倡把容易变化的部分封装起来。
假如是通过用Inject注解标注的构造函数创建类实例,则即使构造函数变的天花乱坠,我们基本上都不需要修改任何代码。

假如是通过工厂模式Module创建类实例,Module其实就是把new类实例的代码封装起来,这样即使类的构造函数发生变化,只需要修改Module即可。

4.利于分工和维护拓展,只需提供接口文档,调用者无需关心构造函数参数


配置
在 APP gradle 配置文件中


由于 Dagger 使用 apt 生成代码,在Project gradle中还需要加入:




结构



Dagger2主要分为4部分:
对象,被调用者, 被依赖注入的类,一般为mvp模式中的p,即presenter
对象的实例化,叫做容器Module
沟通桥梁:将容器和调用者连接起来Component
调用者:需要实例化对象的类,即activity、fragment

对象
public class Person {
   @Inject
    public Person(){
        Log.i("dagger","person create!!!");
    }
}

容器
@Module   //提供依赖对象的实例
public class MainModule {

    @Provides // 关键字,标明该方法提供依赖对象
    Person providerPerson(){
        //提供Person对象
        return new Person();
    }
}

桥梁
@Component(modules = MainModule.class)  // 作为桥梁,沟通调用者和依赖对象库
public interface MainComponent {

    //定义注入的方法
    void inject(MainActivity activity);

}

调用者

public class MainActivity extends AppCompatActivity{

    @Inject   //标明需要注入的对象
    Person person;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // 构造桥梁对象
        MainComponent component = DaggerMainComponent.builder().mainModule(new MainModule()).build();

        //注入
        component.inject(this);

    }
}

解释下连接桥梁初始化



MainComponent是定义的桥梁,build后会build目录自动生成DaggerMainComponent类,类名由Dagger和MainComponent组成,接下来的.mainModule 方法名也不是固定的,
是由MainComponent中modules = MainModule.class决定的。总之桥梁的实例化是会根据桥梁的类名和类里面依赖的父类、使用的容器多个因素决定的。


DaggerMainComponent类




MainComponent




逻辑描述

1.    在Application构建全局component,app初始化即执行
注意要在AnroidMainfest.xml中给application标明执行的类名,即 android:name=".app.RXRetrofitApplication"



全局AppComonent里面注明连接的容器以及向子容器传递的对象,inject表示调用者

如上所示,向子桥梁传递了MainViewInteraction对象,这个对象见InteractorModule:




2.    子桥梁 继承主桥梁(AppComonent),在子桥梁里面的容器MainActivityModule可以使用主桥梁传递过来的对象




依赖注入有个特性,被依赖注入的对象若有参数传递,参数也必须依赖注入,MainViewInteraction有参数WeatherApiService, 依赖注入WeatherApiService, 然后再依赖注入Retrofit,Retrofit里return RestApiAdapter.getInstance(), RestApiAdapter.getInstance()即为Retrofit网络访问相关逻辑。



3.    Activity依赖注入Presenter对象,构建本activity的桥梁


MainActivityComponent继承appComponent,连接mainActivityModule
,并且将本activity作为参数传进去。在mainActivityModule里标注了MainViewPresenter,执行new MainViewPresenterImpl(mainView, mainViewInteraction),本activity 赋值给了mainView,回调mainView接口中的showWeatherInfor,mainViewInteraction参数封装了Retrofit
当点击text,则把参数传给mainViewPresenter


由于load方法加了监听,会回调onFinished
方法,执行showWeatherInfor方法,就把指定地点的天气信息显示出来




注解解释

@Module:作为实例对象的容器。
@Provides:标注能够提供实例化对象的方法。
@Component:作为桥梁,注入对象的通道。
@Inject:需要注入的方法

调用者使用@Inject标识被调用者, 并构建桥梁。
桥梁使用@Component, 并标识依赖的父桥梁、连接的容器、子桥梁、将连接的容器中指定的方法传给子桥梁中的容器几个因子。
容器使用@Module,提供依赖对象@Provides
被调用者使用@Inject,表明被调用的方法

其中容器和被调用者设计的@Provides和@Inject,是先搜索容器中@Provides标示的对象,如果没有,再去搜索@Inject,个人觉得都写上更好点

@Singleton当前提供的对象将是单例模式 ,一般配合@Provides一起出现,当module出现@Singleton,其对应的Component也必须标注Singleton。

 @Provides // 关键字,标明该方法提供依赖对象
    @Singleton
    Person providerPerson(){
        return new Person();
    }




@Named  对象有多个构造函数,通过@named区分使用哪个。




@Scope作用域注解,通过自定义注解限定注解作用域。
比如@Singleton就是Dagger预先定义的作用域注解。


当有Component依赖于别的Component的情况时,两者的作用域不能相同,必须定义一个新的作用域,在同一Component里面标记的多个activity 依赖注入一个类使用的是同一个对象,如果两个activity分别使用各自的Component对同一个类标记不同的作用域,则引用的是不同的对象。


@Subcomponent 继承,Subcomponent其功能效果优点类似component的dependencies。但是使用@Subcomponent不需要在父component中显式添加子component需要用到的对象,只需要添加返回子Component的方法即可,子Component能自动在父Component中查找缺失的依赖。
//父Component:
@PerApp
@Component(modules=××××)
public AppComponent{
    SubComponent subcomponent();  //1.只需要在父Component添加返回子Component的方法即可
}

//子Component:
@PerAcitivity   //2.注意子Component的Scope范围小于父Component
@Subcomponent(modules=××××)   //3.使用@Subcomponent
public SubComponent{
    void inject(SomeActivity activity);
}

//使用
public class SomeActivity extends Activity{
    public void onCreate(Bundle savedInstanceState){
        ...
        App.getComponent().subCpmponent().inject(this);//4.调用subComponent方法创建出子Component
    }   
}


个人感受
好处:
1.解耦,将依赖的对象实例集中在容器中,供activity或者fragment调用,一般情况会有多个地方访问同一对象,对象构造函数发生变化,只需在容器中修改即可。
2.调用者不需要关心依赖注入对象的初始化,只需关心该对象提供什么功能,使用了相应的什么函数。
3.提供单例模式,使用@singleton就搞定了。
4.结合mvp使用,进一步进行了解耦,利于测试和维护。

缺点:
1.工作量变大,相当于把一个简单的new过程 分解了桥梁、容器、调用与被调用者,还有多个注解,目前没发现这种方式提高了性能的说法。
2.主要是对P层依赖注入,也就是说如果不是mvp架构,dagger就没多大意义了。

相关链接
Demo下载
https://github.com/tuozhaobing/RXRetrofitDaggerMvpDemo.git
https://github.com/niuxiaowei/Dagger2Sample.git

资料学习
http://www.cnblogs.com/zhuyp1015/p/5119727.html
http://blog.csdn.net/u014315849/article/details/51566388
http://www.jianshu.com/p/a23c50cb4094

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值