Dagger2分析学习

来源:互联网 发布:如何做好站内优化 编辑:程序博客网 时间:2024/06/06 03:56

Dagger学习笔记


1.概要

Dagger是为Android和Java平台提供的一个完全静态的,在编译时进行依赖注入的框架,原来是由Square公司维护的然后现在把这堆东西扔给

Google维护了

控制反转(Inversion of Control,缩写Ioc),是面向对象编程中的一种设计原则,可以用来减少计算机代码之间的耦合度,其中最常见的方式是依赖注入

(Dependency Injection),还有一种叫做“依赖查找”(Dependency Lookup),通过控制反转对象在创建的时候,有控制系统内所有对象的外界实体,将其

所有依赖的对象的引用传递给它,也可以说,依赖注入到对象中。

应用Dagger2的依赖库:

项目根目录的配置文件中配置:

buildscript {    dependencies {        classpath 'com.android.tools.build:gradle:2.2.2'        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' (annotation processing tools)//注解处理工具
主要是用在java编译的过程中解析java文件中的注解类型,从而产生代码来替换掉源码中的注解的功能。    }}
//应用apt插件apply plugin: 'com.neenbedankt.android-apt'dependencies {    compile 'com.google.dagger:dagger:2.4'    apt 'com.google.dagger:dagger-compiler:2.4'    provided 'org.glassfish:javax.annotation:10.0-b28'}

依赖注入的三种方式:

public class CoffeeMachinWithInjection implements InjectMaker{    private CoffeeMaker maker;    /*依赖注入的3种常见形式     *No.1  构造函数注入     */    public CoffeeMachinWithInjection(CoffeeMaker maker){        this.maker = maker;    }    //No.2  Setter注入    public void setMaker(CoffeeMaker maker){        this.maker = maker;    }    // //No.3 接口注入    @Override    public void injectMaker(CoffeeMaker maker) {        this.maker = maker;    }    public String makeCoffee(){        return maker.makeCoffee();    }}
上述的表示中我们在平时的代码开发中常使用到的代码开发方式,手动提供注入,解决了使用在类内部使用时new一个新的对象。下面我们看是来对

Dagger2进一步使用讲解。动态的解决掉依赖注入。

在Dagger中我们有六种注解:

1.Inject:两个作用

1.在宿主中表明需要注入的类

2.在需要实例化的类中的构造方法上使用,表明需要注解(没有构造参数的类上号使用,在有构造参数的类中需要使用在module中使用@provides提供)

2.Component:主要是在产生依赖的类之间生成通信的桥梁

3.module:专门用来提供依赖

4.provides:用来在module中专门提供产生依赖的类,主要用来标记提供依赖的方法


这里再说明一个问题,我们有两种方式可以提供依赖,一个是注解了@Inject的构造方法,一个是在Module里提供的依赖,那么Dagger2是怎么选择依赖提供的呢,规则是这样的:

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

由上面的步骤可以看出使用依赖Dagger2时,先查找module中是否提供依赖注入对象,如没有在使用构造方法来新建一个类



2.dagger2调用过程


dagger2的调用流程如上图所示:

Dagger2有三个构建组成:从上到下依次为:

1.依赖需求方(宿主),需要使用对象实例的类。

2.依赖提供方,统一提供实例类型或数据掉用的类。

3.依赖注入构件(Component),负责管理module产生的数据注入到宿主中,在编程中表现为一个接口,编译时apt自动回生成一个以Dagger开头的类。

上图中从上到下依次对应上述的三个部分。下面先分析上面代码的表现形式:

在Activity中得到LoginActivityComponont:

DaggerLoginActivityComponont.builder()                .appComponent(AppGlobalState.getInstances().getComponent())                .loginModule(new LoginModule(this, this))                .volidateModule(new VolidateModule())                .build()                .inject(this);
LoginActivity中使用inject(this)方法来获取建立与依赖注解类相关联。

先查看一下LoginActivityComponont类的实现:

/** * Created by cangck on 17/5/19. */@MainActivityScope@Component(modules = {LoginModule.class, VolidateModule.class}, dependencies = AppComponent.class)public interface LoginActivityComponont {    LoginActivity inject(LoginActivity activity);}

在这个类中我们使用到了的注解说明:@MainActivityScope

@Scope@Retention(RetentionPolicy.RUNTIME)public @interface MainActivityScope {}

@scope又是Dagger2的一个域修饰符,对对象提供的范围的一个限制

@Target(ANNOTATION_TYPE)@Retention(RUNTIME)@Documentedpublic @interface Scope {}
@Singleton实例表示时,单例返回
@Modulepublic class AppModule {    private Application mApplication;    public AppModule(Application application) {        this.mApplication = application;    }    @Singleton    @Provides    public Application provideApplication() {        return mApplication;    }}

LoginModule的实现

@Modulepublic class LoginModule {    private LoginActivity mActivity;    private ILoginView mLoginView;    public LoginModule(LoginActivity activity, ILoginView loginView) {        this.mActivity = activity;        this.mLoginView = loginView;    }    @Provides    public LoginActivity providesActivity() {        return mActivity;    }    @Provides    public ILoginView proivdeLoginView() {        return mLoginView;    }    @MainActivityScope    @Provides    public LoginUserBean getUserData() {        LoginUserBean userBean = new LoginUserBean();        userBean.setName("cck");        userBean.setAge(20);        return userBean;    }    @Provides    public LoginPresenter provideLoginPresenter(LoginActivity activity, ILoginView loginView) {        LoginPresenter presenter = new LoginPresenter(activity, loginView);        return presenter;    }}

@MainActivityScope这个注解是对@Scope的扩展,表示只用在Component组件上使用@MainActivityScope注解是才能调用getUserData方法

  • component 的 inject 函数不要声明基类参数;
  • Scope 注解必须用在 module 的 provide 方法上,否则并不能达到局部单例的效果;
  • 如果 module 的 provide 方法使用了 scope 注解,那么 component 就必须使用同一个注解,否则编译会失败;
  • 如果 module 的 provide 方法没有使用 scope 注解,那么 component 和 module 是否加注解都无关紧要,可以通过编译,但是没有局部单例效果;
  • 对于直接使用 @Inject 构造函数的依赖,如果把 scope 注解放到它的类上,而不是构造函数上,就能达到局部单例的效果了;

@Provides    public ILoginView proivdeLoginView() {        return mLoginView;    }    @Provides    public LoginUserBean getUserData() {        LoginUserBean userBean = new LoginUserBean();        userBean.setName("cck");        userBean.setAge(20);        return userBean;    }
上面代码中使用@provides注解方法,当调用对象时,注解工具会在在方法中查找使用@provides注解的方法,并且根据返回值来确认是通过那个方法来提供数据。

注:方法的调用使用过返回值来确认的

下列类为VolidateModule的实现

/** * Created by cangck on 17/5/19. */@Modulepublic class VolidateModule {}

先列举上面的两个类来作为使用说明就Ok了

我们先观察一下LoginActivityComponont类上我们使用了注解

@MainActivityScope@Component(modules = {LoginModule.class, VolidateModule.class}, dependencies = AppComponent.class)

在上面已经介绍过了LoginActivityComponont类使用了注解@Component之后就好变成了Dagger2中的组件控制器。在观察上图,

@Component的注解参数:1.modules,2.dependencies

1.modules表示当前的Component管理LoginModule,VolidateModule,当需要使用类实例时当前的Component只能从上述的两个类的范围中来查找,不会到其他的类中去找。

2.dependencies:相当于类的继承关系,当前的Component不仅可以从自己管理的类中类获取对象,亦可以使用AppComponent提供的方法来使用。

Dagger2之间的三个组件关联的方式已经介绍完成:

1.LoginActivity中使用inject(this)的方法和Dagger2中的组件Component建立关系。

         2.Component与module建立联系是通过@Component(moudel={aModule.class,BModule.class},dependecies=DComponent.class)
4.Component的声明周期:

1.创建Component实例

 DaggerLoginActivityComponont.builder()                .appComponent(AppGlobalState.getInstances().getComponent())                .loginModule(new LoginModule(this, this))                .volidateModule(new VolidateModule())                .build()                .inject(this);

  1. onCreate()方法调用完成后,Component实例就会因为没有被引用而被垃圾回收器回收.其中传入给Component实例的Module实例也会一同被回收,这也就能说明不同的Component实例之间是没有联系的(Component依赖除外).这里需要注意的是,使用Lazy和Provider时,与该依赖对象有关的Module实例会被Lazy和Provider引用,所以该Module实例不会被垃圾回收器回收
参考:

Dagger2 入门,以初学者角度. Dagger2 入门,以初学者角度.

依赖注入神器:Dagger2详解系列

图文教程

Android常用开源工具(2)-Dagger2进阶

Dagger2 Scope 注解能保证依赖在 component 生命周期内的单例性吗?

demo

Android:dagger2让你爱不释手-重点概念讲解、融合篇






原创粉丝点击