01.Dagger基础用法

关于Dagger2

  • Dagger基础用法
  • 对注解的分类讲解——Inject部分
  • 对注解的分类讲解——Module部分(一)
  • 对注解的分类讲解——Component部分
  • 对注解的分类讲解——Module(二)
  • 对注解的分类讲解——Module(三)
  • 对Dagger中几个类的说明
  • Dagger-Android的使用

前言

本系列博客将对Dagger2进行讲解,包含基础使用和源码分析,尽可能地将常用的和不常用的相关知识点进行讲解并佐以例子来描述这些内容。

Dagger2简介

Dagger是最早由square创建,后被google“收编”进一步优化推出了2.0版本,所以后来就被叫做Dagger2了,本文中可能会出现Dagger和Dagger2两种称呼,它们都表示Dagger2。

Dagger是用于依赖项注入的编译时框架,它不使用反射或运行时字节码生成,而是在编译时进行所有分析,并生成纯Java源代码,属于一种依赖注入的方式。

关于依赖注入

依赖注入可以说是一种设计模式,可以用来减低计算机代码之间的耦合度。

构造函数注入

举个例子来讲,有一个厨师需要一些食材才能进行烹饪,一般我们可以在构造函数中去传入所要依赖的对象,如下代码所示:

public class Chef {

    private Food mFood;
    
    // 构造方法中传入厨师所要的食材
    public Chef(Food food) {
        this.mFood = food;
    }
    
    public void cook() {
        // todo 使用食材进行烹饪
    }
}

在调用的时候需要传入相应的食材对象:

Chef chef = new Chef(new Food());
chef.eat();

其实这就是依赖注入,将一个对象注入到它被需要的类中,常见的依赖注入方式还有:

setter方法注入

public class Chef{

    private Food mFood;
    
    // 通过setter方法传入厨师所要的食材
    public setFood(Food food){
        this.mFood = food;
    }
    
    public void cook() {
        // todo 使用食材进行烹饪
    }
}

接口注入

public interface FoodInject{
    void injectFood(Food food);
}

public class Chef implements FoodInject{
    private Food mFood;
    
    @Override
    public injectFood(Food food){
        this.mFood = food;
    }
}

可以说依赖注入在我们的日常开发中是十分常见的,但是一般的依赖注入会造成一些问题,就是注入方式一改,代码中所用到的地方就要进行大量的修改,会增加维护成本,所以需要去引入Dagger来进行依赖注入。

Dagger2的使用

了解了依赖注入的概念,就直接进入本篇的主题吧,如何来使用Dagger2来进行依赖注入。

Dagger2项目github地址

引入依赖

版本请根据Dagger的现有版本进行替换

dependencies {
    // dagger的引用
    implementation 'com.google.dagger:dagger:2.x'
    annotationProcessor 'com.google.dagger:dagger-compiler:2.x'
    // 如果要使用dagger-android则引用
    implementation 'com.google.dagger:dagger-android:2.x'
    implementation 'com.google.dagger:dagger-android-support:2.x' // if you use the support libraries
    annotationProcessor 'com.google.dagger:dagger-android-processor:2.x'
}

在依赖中我们可以发现Dagger可以分成两类:dagger和dagger-android,那么他们究竟都是什么呢?怎么样来使用呢?接下来会详细来看一下他们所提供的功能。

基本用法实现依赖注入

直接注入方式

我们使用Dagger的最主要的目的是实现依赖注入,那么如何实现依赖注入呢?

最新版本的Dagger有两种实现依赖注入的方式,首先先来实现较为简单的一种方式:

public class DirectlyInject {

    // 构造方法参数为空,在构造方法上加上@Inject注解
    @Inject
    public DirectlyInject() {

    }

    // 用于测试的方法
    public void log() {
        Log.d("Dagger测试", "直接进行依赖注入");
    }
}

创建Component将需要注入的类和DirectlyInject建立联系:

@Component
public interface DirectlyInjectComponent {
    void inject(MainActivity activity);
}

然后在Actiivty中进行注入:

public class DirectlyInjectActivity extends AppCompatActivity {
    
    // 获取注入的对象,需要用@Inject注解标注
    @Inject
    DirectlyInject mDirectlyInject;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // 建立链接
        DaggerDirectlyInjectComponent.create().inject(this);
        // 调用log方法验证是否获取到真实实例
        mDirectlyInject.log();
    }
}

打印信息:

打印结果

复杂注入方式

这样就通过Dagger实现了一个最简单的依赖注入,当然这只是针对没有参数的构造方法,但是在实际的项目中我们会遇到各种各样的复杂情况,例如,A还需要依赖其它的类,并且这个类是第三方类库中提供的。又或者A实现了C接口,我们在编码的时候需要使用依赖导致原则来加强我们的代码的可维护性等等。这个时候,用上面这种方法是没办法实现这些需求的,我们使用Dagger2的主要难点也是因为上面这些原因导致的。

这就需要使用另外一种依赖注入的方式了:

public class ComplexInject {

    private ComplexInjectConfig mConfig;

    // 构造方法里需要依赖其它对象怎么办?
    public ComplexInject(ComplexInjectConfig config) {
        mConfig = config;
    }

    public void log() {
        Log.d("Dagger测试", "复杂的依赖注入");
    }
}
// ComplexInjectConfig 类里面什么也没有,纯粹为了作为参数
public class ComplexInjectConfig {
    
}

当构造参数里需要依赖其它类注入的时候应该怎么办呢?

这里就要通过Module来进行相关依赖了:

// 在ComplexInjectModule类中加入@Module注解
@Module
public class ComplexInjectModule {

    // 需要提供对象类,需要传入一个参数
    // 提供的方式是在方法名上加上 @Provides 注解,另外方法名为 providerXXX
    @Provides
    ComplexInject providerComplexInject(ComplexInjectConfig config) {
        return new ComplexInject(config);
    }

    // 所需要传入的参数只要进行提供就可以让另外的对象类在参数中获取到
    // 提供的方式是在方法名上加上 @Provides 注解,另外方法名为 providerXXX
    @Provides
    ComplexInjectConfig providerComplexInjectConfig() {
        return new ComplexInjectConfig();
    }
}

然后通过Component来进行关联:

// 通过@Component注解来关联需要依赖的Activity和提供依赖的Module
@Component(modules = ComplexInjectModule.class)
public interface ComplexInjectComponent {
    void inject(ComplexInjectActivity activity);
}

最后在Activity中注入:

public class ComplexInjectActivity extends AppCompatActivity {

    // 注入所需要的依赖
    @Inject
    ComplexInject mComplexInject;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_complex_inject);

        // 在调用依赖之前的操作,建立起连接
        // 下面两种方法选其中一种
        // 一般方式,可以在builder()进行其它配置
        DaggerComplexInjectComponent.builder().build().inject(this);
        // create()调用的是builder().build()过程,是一种方法的简化
        DaggerComplexInjectComponent.create().inject(this);

        mComplexInject.log();
    }
}

打印结果:


打印结果

这样就实现了含有复杂构造方法对象的依赖注入。

Dagger实现原理

Dagger实现依赖注入的过程

Dagger依赖注入模型

整个依赖注入的过程中,通过Component作为桥梁连接提供注入对象的module和需要注入对象的Activity或是Fragment,在module中所有的对象都需要提供具体的实例,然后Dagger会通过相应的注解实现处理逻辑,实现依赖注入。

所以可以简单地将Dagger的处理过程分成三部分:

  • Inject部分 —— 需要获取依赖注入的类,如Activity、Fragment
  • Component部分 —— 用于建立连接的桥梁
  • Module部分 —— 像Component提供依赖注入的类

Dagger在背后做了什么?

直接注入方式

通过直接注入方式由于我们需要注入的对象的构造函数为空,所以采取了直接在构造方法上加上@Inject注解的方式,通过这种方式Dagger都帮我们做了什么呢?

Dagger主要帮我们生成了三部分的相关类,来实现实现整个依赖注入过程。

Component部分

在整个注入的过程唯一和我们的项目有直接相关的就是有Activity了,在Activity中能够获取到注入的对象,此外还记得在Activity进行关联的那一行代码吗?

DaggerDirectlyInjectComponent.create().inject(this);

DaggerDirectlyInjectComponent这个类一看就是Dagger通过注解帮我们生成的,那么这个类里都做了一些什么事情呢?

// 实现了DirectlyInjectComponent接口
// 实现的类名:Dagger+Component接口名
public final class DaggerDirectlyInjectComponent implements DirectlyInjectComponent {
    
    // 私有化构造函数,不能通过new的形式新建实例
    private DaggerDirectlyInjectComponent() {

    }

    // 实现接口方法
    @Override
    public void inject(DirectlyInjectActivity activity) {
        injectDirectlyInjectActivity(activity);
    }

    private DirectlyInjectActivity injectDirectlyInjectActivity(DirectlyInjectActivity instance) {
        DirectlyInjectActivity_MembersInjector.injectMDirectlyInject(instance, new DirectlyInject());
        return instance;
    }
    
    // 一般的创建DaggerDirectlyInjectComponent实例方式,进一步能够进行参数配置,之后会讲到
    public static Builder builder() {
        return new Builder();
    }
    
    // 简便写法直接通过build方法创建实例
    public static DirectlyInjectComponent create() {
        return new Builder().build();
    }

    // 内部类Builder,建造者模式
    public static final class Builder {
        // 私有化构造函数,不能通过new的形式新建实例
        private Builder() {
        
        }
        
        // 创建DaggerDirectlyInjectComponent实例
        public DirectlyInjectComponent build() {
            return new DaggerDirectlyInjectComponent();
        }
    }
}

在DaggerDirectlyInjectComponent这个类中,首先感觉到的是使用了建造者模式,而且不能通过构造方法新建实例,在其中有builder()和create()两种创建方法,create()方法表示一种简便的创建实例的方式,而builder()方法可以通过构造者方法进行参数配置(在之后的文章中会讲到)。

当然最为核心的方法还是我们在DirectlyInjectComponent中定义的方法的实现:

// 实现接口方法
@Override
public void inject(DirectlyInjectActivity activity) {
    injectDirectlyInjectActivity(activity);
}

// 将activity和所需依赖传入
private DirectlyInjectActivity injectDirectlyInjectActivity(DirectlyInjectActivity instance) {
    DirectlyInjectActivity_MembersInjector.injectMDirectlyInject(instance, new DirectlyInject());
    return instance;
}

最终调用了DirectlyInjectActivity_MembersInjector的injectMDirectlyInject方法,那么问题来了,这个DirectlyInjectActivity_MembersInjector类又是什么呢?

Inject部分

我们进入到DirectlyInjectActivity_MembersInjector类中来看看做了些什么?通过怎么样的步骤实现了和对应Activity的绑定。

// 绑定的Activity/Fragment名 + _ + MembersInjector
// 实现了MembersInjector接口,将需要绑定的Activity作为泛型传入
public final class DirectlyInjectActivity_MembersInjector implements MembersInjector {
    private final Provider mDirectlyInjectProvider;

    public DirectlyInjectActivity_MembersInjector(Provider mDirectlyInjectProvider) {
        this.mDirectlyInjectProvider = mDirectlyInjectProvider;
    }

    public static MembersInjector create(Provider mDirectlyInjectProvider) {
        return new DirectlyInjectActivity_MembersInjector(mDirectlyInjectProvider);
    }

    @Override
    public void injectMembers(DirectlyInjectActivity instance) {
        injectMDirectlyInject(instance, mDirectlyInjectProvider.get());
    }

    // DaggerDirectlyInjectComponent中调用的方法,给activity的依赖赋值
    public static void injectMDirectlyInject(DirectlyInjectActivity instance, DirectlyInject mDirectlyInject) {
        instance.mDirectlyInject = mDirectlyInject;
    }
}

可以看到在DaggerDirectlyInjectComponent类中我们已经将新创建的DirectlyInject实例传入进来,在injectMDirectlyInject方法中实现了对注入对象的赋值。

到这里就可以通过@Inject的方式在Activity中使用注入的对象了。

另外在DirectlyInjectActivity_MembersInjector类中我们可以发现injectMembers也调用了injectMDirectlyInject方法,这应该是另外一种实现注入对象赋值的操作:

// 根据方法名,猜测通过这个方法将依赖进行注入
@Override
public void injectMembers(DirectlyInjectActivity instance) {
    injectMDirectlyInject(instance, mDirectlyInjectProvider.get());
}

在这个方法中,通过mDirectlyInjectProvider.get()将依赖传入,那这个依赖又是怎么来的呢?

// 通过构造方法创建我们需要进行依赖注入的类的提供者
private final Provider mDirectlyInjectProvider;

public DirectlyInjectActivity_MembersInjector(Provider mDirectlyInjectProvider) {
    this.mDirectlyInjectProvider = mDirectlyInjectProvider;
}

那这样就基本清楚了我们所需要的实例是从哪来的。

Module部分

除了上述两个由Dagger创建的类之外还有一个类DirectlyInject_Factory,它是由在构造函数上的@Inject注解生成的。

// DirectlyInject_Factory实现Factory接口,传入DirectlyInject作为泛型
public final class DirectlyInject_Factory implements Factory {
    private static final DirectlyInject_Factory INSTANCE = new DirectlyInject_Factory();

    // 获取对应的对象实例
    @Override
    public DirectlyInject get() {
        return new DirectlyInject();
    }

    public static DirectlyInject_Factory create() {
        return INSTANCE;
    }

    public static DirectlyInject newInstance() {
        return new DirectlyInject();
    }
}

DirectlyInject_Factory这个类首先有点像工厂模式,向外提供实例,而且Factory这个接口是继承自Provider的,所以实际上在DirectlyInjectActivity_MembersInjector类中的get()方法实现就在DirectlyInject_Factory类中来获取所需要的实例。

这样我们基本理清楚了我们的对象是怎么通过Dagger依赖注入的,能够理解为什么要进行那些步骤了,下面我们再来分析一下通过Module实现的复杂注入方式。

复杂注入方式

Component部分

我们还从Activity中的方法看起:

DaggerComplexInjectComponent.create().inject(this);

进到DaggerComplexInjectComponent中:

public final class DaggerComplexInjectComponent implements ComplexInjectComponent {
    private final ComplexInjectModule complexInjectModule;
    
    // 构造函数私有化,不能通过外部new新的对象,传入ComplexInjectModule
    private DaggerComplexInjectComponent(ComplexInjectModule complexInjectModuleParam) {
        // 给ComplexInjectModule赋值
        this.complexInjectModule = complexInjectModuleParam;
    }

    private ComplexInject getComplexInject() {
        return ComplexInjectModule_ProviderComplexInjectFactory.providerComplexInject(complexInjectModule, ComplexInjectModule_ProviderComplexInjectConfigFactory.providerComplexInjectConfig(complexInjectModule));
    }

    @Override
    public void inject(ComplexInjectActivity activity) {
        injectComplexInjectActivity(activity);
    }

    private ComplexInjectActivity injectComplexInjectActivity(ComplexInjectActivity instance) {
        ComplexInjectActivity_MembersInjector.injectMComplexInject(instance, getComplexInject());
        return instance;
    }
    
    // 一般的创建方法,可以进行相关的配置
    public static Builder builder() {
        return new Builder();
    }

    // 创建实例的简便方法
    public static ComplexInjectComponent create() {
        return new Builder().build();
    }

    public static final class Builder {
        private ComplexInjectModule complexInjectModule;

        private Builder() {
        
        }
        
        // 对外提供了ComplexInjectModule的配置
        public Builder complexInjectModule(ComplexInjectModule complexInjectModule) {
            this.complexInjectModule = Preconditions.checkNotNull(complexInjectModule);
            return this;
        }

        // 在build的过程中创建ComplexInjectModule并将其传入构造函数
        public ComplexInjectComponent build() {
            if (complexInjectModule == null) {
                this.complexInjectModule = new ComplexInjectModule();
            }
        return new DaggerComplexInjectComponent(complexInjectModule);
        }
    }
}

DaggerComplexInjectComponent的建立连接过程中,需要将ComplexInjectModule传入构造方法中来获取Module所提供的几个实例,之后与相应的Activity建立起联系:

private ComplexInject getComplexInject() {
    return ComplexInjectModule_ProviderComplexInjectFactory.providerComplexInject(complexInjectModule,
    ComplexInjectModule_ProviderComplexInjectConfigFactory.providerComplexInjectConfig(complexInjectModule));
}

// 需要实现的方法
@Override
public void inject(ComplexInjectActivity activity) {
    injectComplexInjectActivity(activity);
}

private ComplexInjectActivity injectComplexInjectActivity(ComplexInjectActivity instance) {
    ComplexInjectActivity_MembersInjector.injectMComplexInject(instance, getComplexInject());
    return instance;
}

在需要实现的inject方法中调用了injectComplexInjectActivity(ComplexInjectActivity instance)方法,就进入到了ComplexInjectActivity_MembersInjector中,在分析ComplexInjectActivity_MembersInjector之前先来看一下它所要传入的参数getComplexInject(),这个方法中的实现有点长,主要是ComplexInjectModule_ProviderComplexInjectFactory这个类提供了一些东西,来具体看看这个类

Module部分

ComplexInjectModule_ProviderComplexInjectFactory是根据Module中Provider生成的:

public final class ComplexInjectModule_ProviderComplexInjectFactory implements Factory {
    private final ComplexInjectModule module;

    private final Provider configProvider;

    public ComplexInjectModule_ProviderComplexInjectFactory(ComplexInjectModule module, Provider configProvider) {
        this.module = module;
        this.configProvider = configProvider;
    }

    @Override
    public ComplexInject get() {
        return providerComplexInject(module, configProvider.get());
    }

    public static ComplexInjectModule_ProviderComplexInjectFactory create(ComplexInjectModule module, Provider configProvider) {
        return new ComplexInjectModule_ProviderComplexInjectFactory(module, configProvider);
    }

    // DaggerComplexInjectComponent类中getComplexInject方法所调用的方法
    public static ComplexInject providerComplexInject(ComplexInjectModule instance, ComplexInjectConfig config) {
        return Preconditions.checkNotNull(instance.providerComplexInject(config), "Cannot return null from a non-@Nullable @Provides method");
    }
}

在providerComplexInject方法中可以看到通过ComplexInjectModule的providerComplexInject方法去提供一个实例,需要传入ComplexInjectConfig参数,这个参数是怎么获取的呢?

又要回到ComplexInjectModule_ProviderComplexInjectFactory类中:

// 进一步从ComplexInjectModule_ProviderComplexInjectConfigFactory中获取提供的实例
ComplexInjectModule_ProviderComplexInjectConfigFactory.providerComplexInjectConfig(complexInjectModule)

同样的在根据ComplexInjectConfig所生成的工厂类中获取到参数,这里不再进到源码展示。

当我们最终获取到了所需要的参数后就进入到注入过程了:

private ComplexInjectActivity injectComplexInjectActivity(ComplexInjectActivity instance) {
    ComplexInjectActivity_MembersInjector.injectMComplexInject(instance, getComplexInject());
    return instance;
}

Inject部分

public final class ComplexInjectActivity_MembersInjector implements MembersInjector {
    private final Provider mComplexInjectProvider;

    public ComplexInjectActivity_MembersInjector(Provider mComplexInjectProvider) {
        this.mComplexInjectProvider = mComplexInjectProvider;
    }

    public static MembersInjector create(Provider mComplexInjectProvider) {
        return new ComplexInjectActivity_MembersInjector(mComplexInjectProvider);
    }

    @Override
    public void injectMembers(ComplexInjectActivity instance) {
        injectMComplexInject(instance, mComplexInjectProvider.get());
    }

    // 被调用的方法,将给所需要依赖注入的对象赋值
    public static void injectMComplexInject(ComplexInjectActivity instance, ComplexInject mComplexInject) {
        instance.mComplexInject = mComplexInject;
    }
}

这样就结束了复杂注入方式的讲解,和简单注入方式相比,由于所提供的对象多了要配置的参数,所以需要通过在Module中寻找提供的对象来实现。

整个过程:

Component首先会去Module中找所需要的对象,如果构建对象的过程中需要配置参数,继续在Module中寻找所需要的参数直到最终的无参构造函数,最后将创建的对象赋值给Activity中的对象,完成整个依赖注入过程

总结

讲了Dagger的使用好像还没讲为什么要使用Dagger,小项目不需要使用Dagger,当项目逐渐变得庞大,类之间的相互调用变得复杂的时候,如果需要改动某一个构造函数,就会是整个项目中所有使用到这一个构造函数的地方都进行修改,这不利于我们的维护,而Dagger虽然会编写一些模版代码但是就不存在上述我们所说的问题,所以Dagger这个框架视情况使用吧。

本文主要讲解了Dagger2的基础用法和实现思路,接下来将通过对Dagger的相关注解进行分类来分别讲解。

你可能感兴趣的:(01.Dagger基础用法)