Dagger2 之入门学习

Dagger2 之入门学习_第1张图片
image.png

Dagger2已经出来好久,之前也接触过,但是用的不多,一些没有理解到位的地方,其实Dagger2学习的成本还是蛮高的(对我这个学渣来说).
现在从最基础的来慢慢 的了解.这个神兵利器.

1.什么是Dagger2.

Dagger2是一个依赖注入框架,第一代由大名鼎鼎的Square公司共享出来,第二代则是由谷歌接手后推出的,现在由Google接手维护.

2.什么是依赖注入

依赖注入是一种面向对象的编程模式,它的出现是为了降低耦合性,所谓耦合就是类之间依赖关系,所谓降低耦合就是降低类和类之间依赖关系。可能有的人说自己之前并没有使用过依赖注入,其实真的没有使用过吗?当我们在一个类的构造函数中通过参数引入另一个类的对象,或者通过set方法设置一个类的对象其实就是使用的依赖注入.
伪代码:

//简单的依赖注入,构造方法或者set()方法都属于依赖注入
public class ClassA {
 private ClassB classB;
  public void ClassA(ClassB b) {
      classB = b;
  }
}

发现这里ClassA的构造函数里传了一个参数ClassB, 这个Class就依赖于 classA . 其实这样写代码 有问题的,当你的业务变大了, 发现你要传的东西也慢慢的变多, 当要需要修改的里面的东西的时候,发现里面要改的东西太多了.这样根本不符合开闭原则. 所以Dagger2来解决这个问题.

3.基本配置

1.方式: 通过annotationProcessor就是APT工具中的一种,他是google开发的内置框架,不需要引入

        //dagger2 
    implementation 'com.google.dagger:dagger:2.15'
    annotationProcessor 'com.google.dagger:dagger-compiler:2.15'
}

2.方式:annotationProcessor和android-apt的功能是一样的.APT(Annotation Processing Tool)是一种处理注释的工具,它对源代码文件进行检测找出其中的Annotation,根据注解自动生成代码。 Annotation处理器在处理Annotation时可以根据源文件中的Annotation生成额外的源文件和其它的文件(文件具体内容由Annotation处理器的编写者决定),APT还会编译生成的源文件和原来的源文件,将它们一起生成class文件.不懂 APT 可以看这博客:https://blog.csdn.net/xx326664162/article/details/68490059
<1>首先在你的Project build.gradle中添加如下代码

dependencies {
    classpath 'com.android.tools.build:gradle:2.3.1'
    //添加apt插件
    classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
 }

<2>然后添加依赖(在module的build.gradle中添加如下代码)

apply plugin: 'com.android.application'
apply plugin: 'com.neenbedankt.android-apt'

dependencies {
compile 'com.google.dagger:dagger:2.15'
apt 'com.google.dagger:dagger-compiler:2.15'
}

4.使用方式;

Dagger2 是要配合MVP 模式来写是最好的. mvp 模式后面在慢慢的写.先看一下注解干嘛的.
先创建一类,

public class ClassA {

    @Inject
    public ClassA() {
    }
}

我们只是使用 @Inject 这注解 . 编译代码后,看一下. 发现什么效果都咩有.

Dagger2 之入门学习_第2张图片
image.png

但是在这build 路径下面发现了帮我们生成一个 ClassA_Factory 这个类. 可以看一下这类的代码

// Generated by Dagger (https://google.github.io/dagger).
package view.dome.com.mvp_dragger2_dome;

import dagger.internal.Factory;

public final class ClassA_Factory implements Factory {
  private static final ClassA_Factory INSTANCE = new ClassA_Factory(); //在new ClassA_Factory 对象

  @Override
  public ClassA get() {
    return new ClassA(); //通过get 方法 来创建 classA 这个类
  }

  public static ClassA_Factory create() { 
    return INSTANCE;
  }
}

通过代码可以看到 ClassA_Factory这个类 似乎是一个工厂类,在通过create()创建后,每次调用get()方法都能获得一个ClassA对象。其实通过@Inject注解了一个类的构造方法后,可以让编译器帮助我们产生一个对应的Factory类,通过这个工厂类我们可以通过简单的get()方法获取到ClassA对象!

接下来做一个实验看看Dagger2是不是给我们创建对象. 创建一个Activity类,在这个类中创建一个成员变量ClassA,按照Dagger2给我们的指示,当我们需要一个ClassA,我们只需要在这个成员变量上方加一个@Inject注解,编译器会自动帮我们产生对应的代码,我们就可以直接使用这个ClassA对象了!

public class MainActivity extends AppCompatActivity {

    @Inject
    ClassA classA;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.button_dragger2).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(MainActivity.this,classA.toString(), Toast.LENGTH_SHORT).show();
            }
        });
    }


}

本案例中我们设置一个Button,点击Button后我们打印出这个ClassA对象.
但是看结果给我报一空指针异常,发现.@Inject并没有帮助我们初始化对应的ClassA 对象,或者说,我们的Activity并没有使用刚才我们看到的ClassA_Factory类,不过也可以理解,我们并没有建立Activity和ClassA_Factory类之间的关系嘛。看一下应该怎么样建立联系.

创建Module类以及一个Component接口

public class Dragger2_SimpleModule {

    private MainActivity mainActivity;

    public Dragger2_SimpleModule(MainActivity mainActivity) {
        this.mainActivity =mainActivity;
    }
}
import view.dome.com.mvp_dragger2_dome.MainActivity;

@Component(modules = Dragger2_SimpleModule.class)
public interface Dragger2_SimpleComponent {

    void inject(MainActivity activity);
}

请注意,Module类上方的@Module注解意味着这是一个提供数据的【模块】,而Component接口上方的@Component(modules = Dragger2_SimpleModule.class)说明这是一个【组件】.

现在 我们在Aactivity 里面添加下面的代码看一下. 看是否能创建连接.(写完,代码先要编译一下.)

 @Inject
    ClassA classA;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DaggerDragger2_SimpleComponent.builder()
                //此时dragger2_SimpleModule法是过时方法,因为我们没有使用到任何一个module中提供的对象
               .dragger2_SimpleModule( new Dragger2_SimpleModule(this))
                .build().inject(this);

        findViewById(R.id.button_dragger2).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(MainActivity.this,classA.toString(),Toast.LENGTH_SHORT).show();
            }
        });
    }

现在 发现能运行,也能拿到 classA的对象了.

Module和Component作用详解

下面是一个大神举的栗子 ,感觉是蛮好懂的
我们假设案例中的Activity代表家庭住址,classA代表某个商品,现在我们需要在家(Activity)中使用商品(classA),我们网购下单,商家(代表着案例中自动生成的classA_Factory工厂类)将商品出厂,这时我们能够在家直接获得并使用商品吗?

当然不可能,虽然商品(classA)已经从工厂(Factory)生产出来,但是并没有和家(Activity)建立连接,我们还需要一个新的对象将商品送货上门,这种英雄级的人物叫做——快递员(Component,注入器)。

没错,我们需要这样的一种注入器,将已经生产的classA对象传递到需要使用该classA的容器Activity中,于是我们需要在Activity中增加这样几行代码:

    DaggerDragger2_SimpleComponent.builder()
                //此时dragger2_SimpleModule法是过时方法,因为我们没有使用到任何一个module中提供的对象
               .dragger2_SimpleModule( new Dragger2_SimpleModule(this))
                .build()
                .inject(this);

这就说明快递员Component已经将对象Inject(注入)到了this(Activity)中了,既然快递到家,我们当然可以直接使用classA啦!
Module 可以理解成快递的箱子,里面装载的是我们想要的商品,我们在Module中放入什么商品,快递员(Component)将箱子送到我们家(Activity容器),我们就可以直接使用里面的商品啦!

总结

  1. @Inject : 注入,被注解的构造方法会自动编译生成一个Factory工厂类提供该类对象。

2.@Component: 注入器,类似快递员,作用是将产生的对象注入到需要对象的容器中,供容器使用。

3.@Module: 模块,类似快递箱子,在Component接口中通过@Component(modules =
xxxx.class),将容器需要的商品封装起来,统一交给快递员(Component),让快递员统一送到目标容器中。

Module跟Component源码分析

  1. 看一下 dagger2 帮我们生成了什么代码.


    Dagger2 之入门学习_第3张图片
    image.png

    发现里面有三个类. 看一下主要干嘛的.

2.先来看一下 ClassA_Factory 这个类, 其实这个类在上面已经说过了,
当我们@Inject注解一个类的构造方法时,编译器会自动帮我们生成一个工厂类,负责生产该类的对象,类似于商品的厂家.

3.DaggerDragger2_SimpleComponent 这个类,

// Generated by Dagger (https://google.github.io/dagger).
package view.dome.com.mvp_dragger2_dome.module;

import dagger.internal.Preconditions;
import view.dome.com.mvp_dragger2_dome.ClassA;
import view.dome.com.mvp_dragger2_dome.MainActivity;
import view.dome.com.mvp_dragger2_dome.MainActivity_MembersInjector;

public final class DaggerDragger2_SimpleComponent implements Dragger2_SimpleComponent {
  private DaggerDragger2_SimpleComponent(Builder builder) {}

  public static Builder builder() {
    return new Builder();
  }

  public static Dragger2_SimpleComponent create() {
    return new Builder().build();
  }

  @Override
  public void inject(MainActivity activity) {
    injectMainActivity(activity);
  }

  private MainActivity injectMainActivity(MainActivity instance) {
    MainActivity_MembersInjector.injectClassA(instance, new ClassA());
    return instance;
  }

  public static final class Builder {
    private Builder() {}

    public Dragger2_SimpleComponent build() {
      return new DaggerDragger2_SimpleComponent(this);
    }

    /**
     * @deprecated This module is declared, but an instance is not used in the component. This
     *     method is a no-op. For more, see https://google.github.io/dagger/unused-modules.
     */
    @Deprecated
    public Builder dragger2_SimpleModule(Dragger2_SimpleModule dragger2_SimpleModule) {
      Preconditions.checkNotNull(dragger2_SimpleModule);
      return this;
    }
  }
}

在MainActivity 里面就使用到这个类, 这个类的类名就是Dagger 加上Component接口名,在类上面使用也简单build 调用.

   DaggerDragger2_SimpleComponent.builder()
                //此时dragger2_SimpleModule法是过时方法,因为我们没有使用到任何一个module中提供的对象
               .dragger2_SimpleModule( new Dragger2_SimpleModule(this))
                .build()
                .inject(this);

在mainActivty 代码里 发现 首先是调用 DaggerDragger2_SimpleComponent.builder()再调用 build 这个方法.实际上是通过建造者模式创建了一个新的new Builder(); 而我们在使用的时候 再调用了 .build() 方法 , 这个方法里面就是 new DaggerDragger2_SimpleComponent(this); 这个对象.
其实这里面可以这样用,

     DaggerDragger2_SimpleComponent
//                .builder()
//                //此时dragger2_SimpleModule法是过时方法,因为我们没有使用到任何一个module中提供的对象
//               .dragger2_SimpleModule( new Dragger2_SimpleModule(this))
//                .build()
                .create()
                .inject(this);

直接用 .create() 这个方法, 发现这个方法里面已经帮我new 好了.
再看一下 inject( ) 这个方法, 发现把activity 传进injectMainActivity 这个方法里面,
发现 这里使用了 MainActivity_MembersInjector 这个类的方法了,

DaggerDragger2_SimpleComponent 类

// Generated by Dagger (https://google.github.io/dagger).
package view.dome.com.mvp_dragger2_dome.module;

import dagger.internal.Preconditions;
import view.dome.com.mvp_dragger2_dome.ClassA;
import view.dome.com.mvp_dragger2_dome.MainActivity;
import view.dome.com.mvp_dragger2_dome.MainActivity_MembersInjector;

public final class DaggerDragger2_SimpleComponent implements Dragger2_SimpleComponent {
  private DaggerDragger2_SimpleComponent(Builder builder) {}

  public static Builder builder() {
    return new Builder();
  }

  public static Dragger2_SimpleComponent create() {
    return new Builder().build();
  }

  @Override
  public void inject(MainActivity activity) {
    injectMainActivity(activity);
  }

  private MainActivity injectMainActivity(MainActivity instance) {
    MainActivity_MembersInjector.injectClassA(instance, new ClassA());
    return instance;
  }

  public static final class Builder {
    private Builder() {}

    public Dragger2_SimpleComponent build() {
      return new DaggerDragger2_SimpleComponent(this);
    }

    /**
     * @deprecated This module is declared, but an instance is not used in the component. This
     *     method is a no-op. For more, see https://google.github.io/dagger/unused-modules.
     */
    @Deprecated
    public Builder dragger2_SimpleModule(Dragger2_SimpleModule dragger2_SimpleModule) {
      Preconditions.checkNotNull(dragger2_SimpleModule);
      return this;
    }
  }
}

MainActivity_MembersInjector 这个类

// Generated by Dagger (https://google.github.io/dagger).
package view.dome.com.mvp_dragger2_dome;

import dagger.MembersInjector;
import javax.inject.Provider;

public final class MainActivity_MembersInjector implements MembersInjector {
  private final Provider classAProvider;

  public MainActivity_MembersInjector(Provider classAProvider) {
    this.classAProvider = classAProvider;
  }

  public static MembersInjector create(Provider classAProvider) {
    return new MainActivity_MembersInjector(classAProvider);
  }

  @Override
  public void injectMembers(MainActivity instance) {
    injectClassA(instance, classAProvider.get());
  }

  public static void injectClassA(MainActivity instance, ClassA classA) {
    instance.classA = classA;
  }
}

其实已经很简单了,在该Injector的injectMembers()方法中,已经将Student对象通过ClassA_Factory的get()方法获得,然后直接赋值给Activity的ClassA对象了!
里面就是这个方法 injectClassA(instance, classAProvider.get());

上面是没有带Module的源码解析,现在带上Module 看一下.

  1. 在ClassA 这个类里面 去掉@Inject 这个注解.
package view.dome.com.mvp_dragger2_dome;

import javax.inject.Inject;

public class ClassA {


  public ClassA() {
  }
}

2.Module类(增加一个Provide注解方法)

package view.dome.com.mvp_dragger2_dome.module;

import dagger.Module;
import dagger.Provides;
import view.dome.com.mvp_dragger2_dome.MainActivity;

@Module
public class Dragger2_SimpleModule {

    private MainActivity mainActivity;
   
    public Dragger2_SimpleModule(MainActivity mainActivity) {
        this.mainActivity =mainActivity;
    }

  @Provides
    ClassA provideClassA(){
        return new ClassA();
    }
}

再看一下 MainActivity 里面是怎么用的

       DaggerDragger2_SimpleComponent
//                .builder()
//                //此时dragger2_SimpleModule法是过时方法,因为我们没有使用到任何一个module中提供的对象
//               .dragger2_SimpleModule( new Dragger2_SimpleModule(this))
//                .build()
                    .builder()
                .dragger2_SimpleModule(new Dragger2_SimpleModule(this))
               .build()
                .inject(this);

发现 这里面dragger2_SimpleModule 这方法不再是过时的.
现在 argger 帮我生成什么样的代码.
发现 Factory 这类 发生变化了,

// Generated by Dagger (https://google.github.io/dagger).
package view.dome.com.mvp_dragger2_dome.module;

import dagger.internal.Factory;
import dagger.internal.Preconditions;
import view.dome.com.mvp_dragger2_dome.ClassA;

public final class Dragger2_SimpleModule_ProvideClassAFactory implements Factory {
  private final Dragger2_SimpleModule module;

  public Dragger2_SimpleModule_ProvideClassAFactory(Dragger2_SimpleModule module) {
    this.module = module;
  }

  @Override
  public ClassA get() {
    return Preconditions.checkNotNull(
        module.provideClassA(), "Cannot return null from a non-@Nullable @Provides method");
  }

  public static Dragger2_SimpleModule_ProvideClassAFactory create(Dragger2_SimpleModule module) {
    return new Dragger2_SimpleModule_ProvideClassAFactory(module);
  }

  public static ClassA proxyProvideClassA(Dragger2_SimpleModule instance) {
    return Preconditions.checkNotNull(
        instance.provideClassA(), "Cannot return null from a non-@Nullable @Provides method");
  }
}

Dragger2_SimpleModule_ProvideClassAFactory 这里必须传了 Model .通过@Providers注解后,产生的对象就经过Module包装,通过Component快递员送到需要的容器Activity中。

相比@Inject简单粗暴的注解生成的“万能工厂”ClassA_Factory类,似乎这个更“安全”一些~.
经过两次分析 我们基本理解了Dagger2的使用方式,原理基本如下:

@Inject 注解构造 生成“大众”工厂类
或者
@Module +@Providers 提供注入“私有”工厂类

然后

通过Component 创建获得Activity,获得工厂类Provider,统一交给Injector

最后

Injector将Provider的get()方法提供的对象,注入到Activity容器对应的成员变量中,我们就可以直接使用Activity容器中对应的成员变量了!

你可能感兴趣的:(Dagger2 之入门学习)