dagger2解析

1,概述

在Dagger 2官方文档中,有这么一句话“A fast dependency injector for Android and Java.”,翻译过来的意思就是:适用于Android和Java的快速依赖注入。


image.png
Gradle配置
dependencies {
    implementation 'com.google.dagger:dagger:2.16'
    kapt 'com.google.dagger:dagger-compiler:2.16'
}

2,注入方式(构造方式注入和module注入)

  • 采用构造方法注入,构造方法上加@Inject,并定义带有@Component注解的接口

在Dagger 2中,使用javax.inject.Inject注解来标识需要依赖注入的构造函数和字段,以满足Dagger构造应用应用程序类的实例并满足其依赖性。
@Inject有两项职责:
注解构造函数:通过标记构造函数,告诉Dagger 2可以创建该类的实例(Dagger2通过Inject标记可以在需要这个类实例的时候来找到这个构造函数并把相关实例new出来)从而提供依赖关系。
使用@Component作为依赖注入桥梁,@Component一般用来注解接口,被注解的接口在编译时会产生相应的实例,作为提供依赖和所需依赖之间的桥梁,把相关依赖注入到其中

class StudentBean @Inject constructor(){
    var num: Int = 1
    var name: String = "赵四"
}

class TeacherBean @Inject constructor(var studentBean: StudentBean)
@Component
interface MainCompoment {
    fun inject(test1Activity: Test1Activity)
}
/**
 * 构造方式注入
 */
class Test1Activity : AppCompatActivity() {

    @Inject
    internal lateinit var studentBean: StudentBean

    @Inject
    internal lateinit var teacherBean: TeacherBean

    @SuppressLint("SetTextI18n")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activityt_test1)
        DaggerMainCompoment.create().inject(this)

        text.text = "学生: " + studentBean.name + studentBean.num
        text2.text = "老师: " + teacherBean.studentBean.name + teacherBean.studentBean.num
    }
}

运行之后如下:


image.png

看下变成生成的代码:

public final class DaggerMainCompoment implements MainCompoment {
  private DaggerMainCompoment(Builder builder) {}

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

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

  private TeacherBean getTeacherBean() {
    return new TeacherBean(new StudentBean());
  }

  @Override
  public void inject(Test1Activity test1Activity) {
    injectTest1Activity(test1Activity);
  }

//injectStudentBean方法将StudentBean和TeacherBean注入到了Test1Activity中
  private Test1Activity injectTest1Activity(Test1Activity instance) {
    Test1Activity_MembersInjector.injectStudentBean(instance, new StudentBean());
    Test1Activity_MembersInjector.injectTeacherBean(instance, getTeacherBean());
    return instance;
  }

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

    public MainCompoment build() {
      return new DaggerMainCompoment(this);
    }
  }
}
public final class Test1Activity_MembersInjector implements MembersInjector<Test1Activity> {
  private final Provider<StudentBean> studentBeanProvider;

  private final Provider<TeacherBean> teacherBeanProvider;

  public Test1Activity_MembersInjector(
      Provider<StudentBean> studentBeanProvider, Provider<TeacherBean> teacherBeanProvider) {
    this.studentBeanProvider = studentBeanProvider;
    this.teacherBeanProvider = teacherBeanProvider;
  }

  public static MembersInjector<Test1Activity> create(
      Provider<StudentBean> studentBeanProvider, Provider<TeacherBean> teacherBeanProvider) {
    return new Test1Activity_MembersInjector(studentBeanProvider, teacherBeanProvider);
  }

  @Override
  public void injectMembers(Test1Activity instance) {
    injectStudentBean(instance, studentBeanProvider.get());
    injectTeacherBean(instance, teacherBeanProvider.get());
  }

  public static void injectStudentBean(Test1Activity instance, StudentBean studentBean) {
    instance.studentBean = studentBean;
  }

  public static void injectTeacherBean(Test1Activity instance, TeacherBean teacherBean) {
    instance.teacherBean = teacherBean;
  }
}

2,采用@module,通过@provide注解提供依赖

对于module的解释是注解的类为Dagger提供依赖关系。
之前已经提到了,@Inject可以提供依赖关系,但是其不是万能的。如果我们所需要的提供的构造函数没有使用@Inject注解,那么Module类可以在不修改构造函数的情况下,通过provide提供依赖关系。即使是可以用@Inject注解的,依然可以通过Module提供依赖关系。

这里,我们需要明确的一个概念是@Module注解的类,是向Dagger提供依赖关系

  • 定义module类,通过provide提供实例
@Module
class MainModule {

    @Provides
    fun provideStudentBean(): StudentBean = StudentBean()

    @Provides
    fun provideTeacherBean(studentBean: StudentBean): TeacherBean = TeacherBean(studentBean)
}
  • 这里因为使用module,Activity中Component注入的方式有所改变,需要使用DaggerMainCompoment中Builder提供module并创建,如下
/**
 * 通过module进行注入
 */
class Test2Activity : AppCompatActivity() {

    @Inject
    internal lateinit var studentBean: StudentBean

    @Inject
    internal lateinit var teacherBean: TeacherBean

    @SuppressLint("SetTextI18n")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activityt_test2)
        DaggerMainCompoment.builder()
                .mainModule(MainModule())
                .build()
                .inject(this)

        text.text = "学生: " + studentBean.name + studentBean.num
        text2.text = "老师: " + teacherBean.studentBean.name + teacherBean.studentBean.num

    }
}

最终结果展示如下


image.png
  • 那么我们来看看编译生成的代码,DaggerMainCompoment增加了injectTest2Activity的代码,如下
private Test2Activity injectTest2Activity(Test2Activity instance) {
    Test2Activity_MembersInjector.injectStudentBean(
        instance, MainModule_ProvideStudentBeanFactory.proxyProvideStudentBean(mainModule));
    Test2Activity_MembersInjector.injectTeacherBean(instance, getTeacherBean());
    return instance;
  }

  public static final class Builder {
    private MainModule mainModule;

    private Builder() {}

    public MainCompoment build() {
      if (mainModule == null) {
        this.mainModule = new MainModule();
      }
      return new DaggerMainCompoment(this);
    }

    public Builder mainModule(MainModule mainModule) {
      this.mainModule = Preconditions.checkNotNull(mainModule);
      return this;
    }
  }

通过创建Builder,提供了mainModule的实例,并传到MainCompoment

Test2Activity_MembersInjector.injectStudentBean(
        instance, MainModule_ProvideStudentBeanFactory.proxyProvideStudentBean(mainModule));

通过proxyProvideStudentBean方法获取StudentBean实例,代码如下:

 public static StudentBean proxyProvideStudentBean(MainModule instance) {
    return Preconditions.checkNotNull(
        instance.provideStudentBean(), "Cannot return null from a non-@Nullable @Provides method");
  }

通过MainModule.取到了该类中提供的StudentBean实例,最后一步往下看

public static void injectStudentBean(Test2Activity instance, StudentBean studentBean) {
    instance.studentBean = studentBean;
  }

injectStudentBean方法将获取到的studentBean赋值给了Test2Activity

  • 再来看一下显示提供依赖的实现,增加provideStudentBean方法
@Component(modules = [MainModule::class])
interface MainCompoment {

    fun inject(test1Activity: Test1Activity)

    fun inject(test2Activity: Test2Activity)

    fun provideStudentBean(): StudentBean
}

如下调用

 val build = DaggerMainCompoment.builder()
                .mainModule(MainModule())
                .build()
        build.inject(this)

        val provideStudentBean = build.provideStudentBean()
        Log.e("test2", provideStudentBean.name + provideStudentBean.num)

此方法provideStudentBean,最终会在DaggerMainCompoment进行实现,最终还是调用到MainModule中提供的实例

 @Override
  public StudentBean provideStudentBean() {
    return MainModule_ProvideStudentBeanFactory.proxyProvideStudentBean(mainModule);
  }

 public static StudentBean proxyProvideStudentBean(MainModule instance) {
    return Preconditions.checkNotNull(
        instance.provideStudentBean(), "Cannot return null from a non-@Nullable @Provides method");
  }

此前生成的bean生成的代码还一直未使用如下,先放着

public final class StudentBean_Factory implements Factory<StudentBean> {
  private static final StudentBean_Factory INSTANCE = new StudentBean_Factory();

  @Override
  public StudentBean get() {
    return provideInstance();
  }

  public static StudentBean provideInstance() {
    return new StudentBean();
  }

  public static StudentBean_Factory create() {
    return INSTANCE;
  }

  public static StudentBean newStudentBean() {
    return new StudentBean();
  }
}

3, @Qualifier限定符

  • 提供相同返回值的依赖,会造成Dagger的“依赖迷失”,无法确定提供哪个依赖
    可通过自定义注解进行区分,如下不做详解
@Module()
public class FruitModule {

    //使用限定符来区别使用哪个构造函数返回对象
    @Type("color")
    @Provides
    public AppleBean provideColorApple() {
        return new AppleBean("red");
    }

    @Type("name")
    @Provides
    public AppleBean provideNameApple() {
        return new AppleBean("红富士", 6.88);
    }
}

4,@Scope作用域

作用域的理解是变量的作用范围,因此,出现了全局变量和局部变量之分
同vue中css使用scope,表示css只在当前页面生效;所以scope如同设定提供依赖的声明周期一样.如定义的@AppScope在App进行build,最终生命周期是整个app,如定义的@ActivityScope是在Activity中build,那么生命周期同activity

如果使用了@Scope注解了该类,注入器会缓存第一次创建的实例,然后每次重复注入缓存的实例,而不会再创建新的实例

接下来结合代码实例讲解,只有BoysBean添加@ActivityScope
(如果MainCompoment中module有使用scope,则Component需要有该scope)

    @Provides
    fun provideGirlsBean(): GirlsBean = GirlsBean()

    @ActivityScope
    @Provides
    fun provideBoysBean(): BoysBean = BoysBean()
   @Inject
    internal lateinit var boysBean: BoysBean
    @Inject
    internal lateinit var boysBean2: BoysBean

    @Inject
    internal lateinit var girlsBean: GirlsBean
    @Inject
    internal lateinit var girlsBean2: GirlsBean

     Log.e("test2", "girlsBean  " + girlsBean.toString())
     Log.e("test2", "girlsBean2  " + girlsBean2.toString())
     Log.e("test2", "boysBean  " + boysBean.toString())
     Log.e("test2", "boysBean2  " + boysBean2.toString())

2018-08-20 21:19:49.388 2417-2417/com.plugin.gradle.lucio.dagger2 E/test2: girlsBean  com.plugin.gradle.lucio.dagger2.domain.GirlsBean@c287b9a
2018-08-20 21:19:49.388 2417-2417/com.plugin.gradle.lucio.dagger2 E/test2: girlsBean2  com.plugin.gradle.lucio.dagger2.domain.GirlsBean@601bccb
2018-08-20 21:19:49.388 2417-2417/com.plugin.gradle.lucio.dagger2 E/test2: boysBean  com.plugin.gradle.lucio.dagger2.domain.BoysBean@6456ca8
2018-08-20 21:19:49.388 2417-2417/com.plugin.gradle.lucio.dagger2 E/test2: boysBean2  com.plugin.gradle.lucio.dagger2.domain.BoysBean@6456ca8

可见带@ActivityScope的bean进行缓存了,我们来看看DaggerMainCompoment生成的代码的区别

 private void initialize(final Builder builder) {
    this.mainModule = builder.mainModule;
    this.provideBoysBeanProvider =
        DoubleCheck.provider(MainModule_ProvideBoysBeanFactory.create(builder.mainModule));
  }

由BoysBean类生成的factory代码开始使用,通过create创建了MainModule_ProvideBoysBeanFactory,并通过get()提供BoysBean实例

 @Override
  public BoysBean get() {
    return provideInstance(module);
  }

public static MainModule_ProvideBoysBeanFactory create(MainModule module) {
    return new MainModule_ProvideBoysBeanFactory(module);
  }

同时使用DoubleCheck.provider保持bean的单例

public static <P extends Provider<T>, T> Provider<T> provider(P delegate) {
    checkNotNull(delegate);
    if (delegate instanceof DoubleCheck) {
      /* This should be a rare case, but if we have a scoped @Binds that delegates to a scoped
       * binding, we shouldn't cache the value again. */
      return delegate;
    }
    return new DoubleCheck<T>(delegate);
  }

最后看看两者bean的区别

 private Test2Activity injectTest2Activity(Test2Activity instance) {
    Test2Activity_MembersInjector.injectStudentBean(
        instance, MainModule_ProvideStudentBeanFactory.proxyProvideStudentBean(mainModule));
    Test2Activity_MembersInjector.injectTeacherBean(instance, getTeacherBean());
    Test2Activity_MembersInjector.injectBoysBean(instance, provideBoysBeanProvider.get());
    Test2Activity_MembersInjector.injectBoysBean2(instance, provideBoysBeanProvider.get());
    Test2Activity_MembersInjector.injectGirlsBean(
        instance, MainModule_ProvideGirlsBeanFactory.proxyProvideGirlsBean(mainModule));
    Test2Activity_MembersInjector.injectGirlsBean2(
        instance, MainModule_ProvideGirlsBeanFactory.proxyProvideGirlsBean(mainModule));
    return instance;
  }

BoysBean通过provideBoysBeanProvider.get()获取,GirlsBean通过 MainModule_ProvideGirlsBeanFactory.proxyProvideGirlsBean(mainModule)重新创建,由此可见BoysBean的实例随activity生命周期

5,多个元素绑定并注入到Set

将多个元素注入到Set中,不仅支持单个元素注入到Set中,同时支持子Set<T>注入到Set中。

@Module()
public class FruitModule {

    @Provides
    @IntoSet
    public BananaBean providerBanana() {
        return new BananaBean("特朗普香蕉");
    }
}
@Module() 
public class DrinkModule {

@Provides
@IntoSet
public BananaBean providerBanana() {
    return new BananaBean("巴拿马香蕉");
}

将子Set<T>注入到Set:

@Module()
public class FruitModule {
    @Provides
    @ElementsIntoSet
    public Set<BananaBean> providerBananaSet() {
        Set<BananaBean> set = new HashSet<>();
        set.add(new BananaBean("布什香蕉"));
        set.add(new BananaBean("约翰逊香蕉"));
        return set;
    }
}
class Test3Activity : AppCompatActivity() {

    @Inject
    internal lateinit var studentBean: Set<BananaBean>

    @SuppressLint("SetTextI18n")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activityt_test3)
        DaggerMainCompoment.create().inject(this)

        val stringBuilder1 = StringBuilder()
        studentBean.forEach {
            stringBuilder1.append(it.name + "  ")
        }
        text.text = stringBuilder1
    }
}

生成代码同上,不做分析,测试结果如下


image.png

5,多个元素绑定并注入到Map

Dagger不仅可以将绑定的多个元素依赖注入到Set,还可以将绑定的多个元素依赖注入到Map。与依赖注入Set不同的是,依赖注入Map时,必须在编译时指定Map的Key,那么Dagger向MapMap注入相应的元素。
对于向Map提供元素的@Provides方法,需要使用@IntoMap,同时指定该元素的Key(例如@StringKey(“foo”)、@ClassKey(Thing.class))。

  • 我们先以StringKey、ClassKey注解为例注入Map:
    @Provides
    @IntoMap // 指定该@Provides方法向Map提供元素
    @StringKey("A") // 指定该元素在Map中所对应的的Key
    fun providerApple(): AppleBean = AppleBean("A苹果")

    @Provides
    @IntoMap
    @ClassKey(Test3Activity::class)
    fun providerAppleMap(): AppleBean = AppleBean("北京苹果")
  • 获取依赖
class Test3Activity : AppCompatActivity() {

    @Inject
    internal lateinit var studentBean: Set<BananaBean>
    @Inject
    internal lateinit var appleBean: Map<String, AppleBean>
    @Inject
    internal lateinit var appleBean2: Map<Class<*>, AppleBean>

    @SuppressLint("SetTextI18n")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activityt_test3)
        DaggerMainCompoment.create().inject(this)

        val stringBuilder1 = StringBuilder()
        val stringBuilder2 = StringBuilder()
        val stringBuilder3 = StringBuilder()
        studentBean.forEach {
            stringBuilder1.append(it.name + "  ")
        }
        appleBean.forEach {
            stringBuilder2.append(it.value.name + "  ")
        }
        appleBean2.forEach {
            stringBuilder3.append(it.value.name + "  ")
        }
        text.text = stringBuilder1
        text2.text = stringBuilder2
        text3.text = stringBuilder3

    }
}

结果如下:


image.png

6,自定义Key

在注释类型中声明的方法的返回类型,如果不满足指定的返回类型,那么编译时会报错:
基本数据类型
String
Class
枚举类型
注解类型
以上数据类型的数组

@MapKey
public @interface MyNumberClassKey {
  Class<? extends Number> value();
}

@Provides
@IntoMap
@MyNumberClassKey(BigDecimal::class)
fun provideBigDecimalValue(): String = "value for BigDecimal"

 @Inject
 internal lateinit var enum2: Map<Class<out Number>, String>

 enum2.forEach { stringBuilder5.append(it.value) }
 text5.text = stringBuilder5

结果如下


image.png

7,Component依赖关系

在使用Dagger 2开发时,一般都是在Application中生成一个AppComponent,然后其他的功能模块的Component依赖于AppComponent,作为AppComponent的子组件。可是,对于将自组建添加到父组件有两种方式:

  • 通过@Component的dependencies属性依赖父组件
@Component(modules = OrangeModule.class, dependencies = FruitComponent.class)
public interface OrangeComponent {}
  • 通过Moudle的subcomponents属性添加子组件
@Module(subcomponents = AppleSubcomponent.class)
public class FruitModule {}

Subcomponents(子组件)和组件依赖最大的不同是当你接入父组件的时候,你可以访问它所有模块的所有对象而无需显示声明依赖父组件,而组件依赖必须显示提供依赖,后面做详解

  • Subcomponent的介绍

对于继承,大家应该都不陌生,其实就是子类继承父类,子类自动获取了的父类的属性和行为。我觉得我们也可以这么认为子组件。子组件是继承和扩展父组件的对象的组件

  • 添加子组件

声明子组件,与普通组件声明类似,可以通过编写一个抽象类或接口来创建一个子组件,该类或接口声明了返回应用程序相关的类型的抽象方法。可以使用@Component,也可以使用@Subcomponent注解,这个没有一定的强制性。

与@Component注解不同的是,使用@Subcomponent注解子组件,必须声明其xxComponent.Builder,否则编译时,会报错。

@Subcomponent(modules = AppleModule.class)
public interface AppleSubcomponent {

    AppleBean supplyApple();

    @Subcomponent.Builder
    interface Builder{
        Builder appleModule(AppleModule module);
        AppleSubcomponent build();
    }
}
通过@Component的dependencies属性依赖父组件

注意:
子类的作用域和父类的不能一样,要不然会报以下错误
SecondComponent depends on scoped components in a non-hierarchical scope ordering:

依赖Component(OrangeComponent) 仅继承 被依赖Component(FruitComponent) 中显示提供的依赖。如果被依赖Component(FruitComponent)必须提供依赖注入的对象,也就是将对象实例暴露出来。否则,在子组件,也就是依赖Component(OrangeComponent)中,无法使用@Inject注入被依赖的Component(AppComponent)中的对象,此时编译器会报错,提示依赖注入的Xx实例没有提供@Inject注解或者@Provides方法。

@SubScope
@Component(dependencies = [MainCompoment::class])
interface DeComponent {
    fun inject(test4Activity: Test4Activity)
}
class Test4Activity : AppCompatActivity() {

    @Inject
    internal lateinit var studentBean: StudentBean

    @Inject
    internal lateinit var girlsBean: GirlsBean

    @SuppressLint("SetTextI18n")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activityt_test4)
        DaggerDeComponent.builder()
                .mainCompoment(DaggerMainCompoment.create())
                .build()
                .inject(this)

        text.text = studentBean.name
        text2.text = girlsBean.name
    }
}

结果如下


image.png

我们来看一下DaggerDeComponent中生成的代码

  • 首先initialize中获取了mainCompoment
 @SuppressWarnings("unchecked")
  private void initialize(final Builder builder) {
    this.mainCompoment = builder.mainCompoment;
  }
  • 这里通过provideStudentBean方法直接取到了显示提供的依赖,最后注入到Test4Activity
 private Test4Activity injectTest4Activity(Test4Activity instance) {
    Test4Activity_MembersInjector.injectStudentBean(
        instance,
        Preconditions.checkNotNull(
            mainCompoment.provideStudentBean(),
            "Cannot return null from a non-@Nullable component method"));
    Test4Activity_MembersInjector.injectGirlsBean(
        instance,
        Preconditions.checkNotNull(
            mainCompoment.provideGirlsBean(),
            "Cannot return null from a non-@Nullable component method"));
    return instance;
  }
  • 测试一下不显示的提供依赖会有什么结果, 编译时DeComponent会报错
/Users/lucio/Documents/third_frame/dagger2/app/build/tmp/kapt3/stubs/debug/com/plugin/gradle/lucio/dagger2/di/component/DeComponent.java:17: error: [Dagger/MissingBinding] com.plugin.gradle.lucio.dagger2.domain.GirlsBean cannot be provided without an @Inject constructor or an @Provides-annotated method.
    public abstract void inject(@org.jetbrains.annotations.NotNull()
                         ^
      com.plugin.gradle.lucio.dagger2.domain.GirlsBean is injected at
          com.plugin.gradle.lucio.dagger2.ui.Test4Activity.girlsBean
      com.plugin.gradle.lucio.dagger2.ui.Test4Activity is injected at
          com.plugin.gradle.lucio.dagger2.di.component.DeComponent.inject(com.plugin.gradle.lucio.dagger2.ui.Test4Activity)

通过Moudle的subcomponents属性添加子组件

@SubComponent的写法与@Component一样,只能标注接口或抽象类,与依赖关系一样,SubComponent 与 parent Component 的 Scope 不能相同,只是 SubComponent 表明它是继承扩展某 Component 的。怎么表明一个 SubComponent 是属于哪个 parent Component 的呢?只需要在 parent Component 依赖的 Module 中的subcomponents加上 SubComponent 的 class,然后就可以在 parent Component 中请求 SubComponent.Builder。

@Subcomponent(modules = [AppleModule::class])
interface SonComponent {

    fun inject(test5Activity: Test5Activity)

    @Subcomponent.Builder
    interface Builder {
        fun appleModule(module: AppleModule): Builder
        fun build(): SonComponent
    }
}

MainModule添加SonComponent的subcomponents

@Module(subcomponents = [SonComponent::class])
class MainModule {

    @Provides
    fun provideStudentBean(): StudentBean = StudentBean()

    @Provides
    fun provideTeacherBean(studentBean: StudentBean): TeacherBean = TeacherBean(studentBean)

    @Provides
    fun provideGirlsBean(): GirlsBean = GirlsBean()

    @ActivityScope
    @Provides
    fun provideBoysBean(): BoysBean = BoysBean()
}

MainCompoment中添加fun sonComponent(): SonComponent.Builder

@ActivityScope
@Component(modules = [MainModule::class, DrinkModule::class, FruitModule::class, CusMapKeyModule::class])
interface MainCompoment {

    fun inject(test1Activity: Test1Activity)

    fun inject(test2Activity: Test2Activity)

    fun inject(test3Activity: Test3Activity)

    fun provideStudentBean(): StudentBean

    fun provideGirlsBean(): GirlsBean

    fun sonComponent(): SonComponent.Builder  // 用来创建 Subcomponent
}
  • 我们先获取MainModule中StudentBean和TeacherBean
class Test5Activity : AppCompatActivity() {

    @Inject
    internal lateinit var studentBean: StudentBean

    @Inject
    internal lateinit var teacherBean: TeacherBean

    @SuppressLint("SetTextI18n")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activityt_test1)

        DaggerMainCompoment.create()
                .sonComponent()
                .build()
                .inject(this)

        text.text = "学生: " + studentBean.name + studentBean.num
        text2.text = "老师: " + teacherBean.studentBean.name + teacherBean.studentBean.num

    }
}

结果如下


image.png

我们来看一下生成的代码,如果取到parent Component的依赖

  • 首先通过sonComponent创建SonComponentBuilder
@Override
  public SonComponent.Builder sonComponent() {
    return new SonComponentBuilder();
  }
  • 通过SonComponentBuilder中build创建SonComponentImpl,再调用inject方法,
    到这里我们就发现, SonComponentImpl是MainComponent的内部类,自然可以获取到外部类MainComponent的mainModule和getTeacherBean()方法,通过mainModule则获取到StudentBean,getTeacherBean()获取到TeacherBean,
    Test5Activity_MembersInjector. injectStudentBean()和injectTeacherBean()则注入到Test5Activity
 private final class SonComponentBuilder implements SonComponent.Builder {
    @Override
    public SonComponent build() {
      return new SonComponentImpl(this);
    }

    /**
     * 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.
     */
    @Override
    public SonComponentBuilder appleModule(AppleModule module) {
      return this;
    }
  }

  private final class SonComponentImpl implements SonComponent {
    private SonComponentImpl(SonComponentBuilder builder) {}

    @Override
    public void inject(Test5Activity test5Activity) {
      injectTest5Activity(test5Activity);
    }

    private Test5Activity injectTest5Activity(Test5Activity instance) {
      Test5Activity_MembersInjector.injectStudentBean(
          instance,
          MainModule_ProvideStudentBeanFactory.proxyProvideStudentBean(
              DaggerMainCompoment.this.mainModule));
      Test5Activity_MembersInjector.injectTeacherBean(
          instance, DaggerMainCompoment.this.getTeacherBean());
      return instance;
    }
  }
}

再看看获取AppleModule中的依赖

@Inject
internal lateinit var studentBean: StudentBean

 text3.text = "apple:  " + appleBean.name

结果如下


image.png

看看生成的代码, build中创建了AppleModule, injectAppleBean则进行了注入

 @Override
    public SonComponent build() {
      if (appleModule == null) {
        this.appleModule = new AppleModule();
      }
      return new SonComponentImpl(this);
    }

Test5Activity_MembersInjector.injectAppleBean(
          instance, AppleModule_PrivdeAppleFactory.proxyPrivdeApple(appleModule));

8,完美扩展库-dagger.android

  • Dagger的使用流程

1,在ApplicationComponent中注入AndroidInjectionModule,如果项目中用到v4包的Fragment,还需注入AndroidSupportInjectionModule.建议把两个Module都注入XxComponent中

@Component(modules = [
    AndroidInjectionModule::class,
    AndroidSupportInjectionModule::class])
interface AppComponent {
    fun inject(instance: App?)
}

2,创建子组件 - @Subcomponent,其继承自AndroidInjector<T>,而T就是step2创建的Android库的类型

@Subcomponent(modules = [MainModule::class])    //这里需要MainModule,否则会关联不上
interface SonComponent : AndroidInjector<MainActivity> {

    @Subcomponent.Builder
    abstract class Builder : AndroidInjector.Builder<MainActivity>()
}

3,创建Module,其subcomponents属性值就是step3创建的子组件。在其内必须声明一个抽象方法,该抽象方法返回AndroidInjector.Factory<?>实例,而其参数为step1创建的XxSubcomponent.Builder实例。

@Module(subcomponents = [SonComponent::class])
abstract class ActivityBuilder {

    @Binds
    @IntoMap
    @ActivityKey(MainActivity::class)
    internal abstract fun bindYourActivityInjectorFactory(builder: SonComponent.Builder): AndroidInjector.Factory<out Activity>
}

4,将创建的Module注入到ApplicationComponent中,即把其添加至ApplicationComponent的modules属性列表,即添加ActivityBuilder

@Component(modules = [
    AndroidInjectionModule::class,
    AndroidSupportInjectionModule::class,
    ActivityBuilder::class])
interface AppComponent {
    fun inject(instance: App?)
}

5,创建Application。实现HasActivityInjector, HasSupportFragmentInjector支持activity和fragment的注解。

class App : Application(), HasActivityInjector, HasSupportFragmentInjector {

    //依赖注入的核心原则:一个类不应该知道如何实现依赖注入。
    @Inject
    internal lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Activity>
    @Inject
    internal lateinit var fragmentSupportInjector: DispatchingAndroidInjector<Fragment>

    override fun onCreate() {
        super.onCreate()
        DaggerAppComponent.create().inject(this)
    }

    override fun activityInjector(): AndroidInjector<Activity>? = dispatchingAndroidInjector

    override fun supportFragmentInjector(): AndroidInjector<Fragment> = fragmentSupportInjector
}

6,添加module提供依赖

@Module
class MainModule {
    @Provides
    fun providesBoysBean(): BoysBean = BoysBean()
}

@Subcomponent(modules = [MainModule::class])    //这里需要MainModule,否则会关联不上
interface SonComponent : AndroidInjector<MainActivity> {

    @Subcomponent.Builder
    abstract class Builder : AndroidInjector.Builder<MainActivity>()
}

7,创建Android库的核心类,需要注意的就是:AndroidInjection.inject(T)方法的调用位置,即可展示出来

class MainActivity : AppCompatActivity() {

    @Inject
    internal lateinit var boysBean: BoysBean

    override fun onCreate(savedInstanceState: Bundle?) {
        AndroidInjection.inject(this)
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        text.text = boysBean.name
    }
}

我们来看一下生成的DaggerAppComponent

// Generated by Dagger (https://google.github.io/dagger).
package com.plugin.gradle.lucio.dagger_android.di.component;

import android.app.Activity;
import androidx.fragment.app.Fragment;
import com.plugin.gradle.lucio.dagger_android.App;
import com.plugin.gradle.lucio.dagger_android.App_MembersInjector;
import com.plugin.gradle.lucio.dagger_android.MainActivity;
import com.plugin.gradle.lucio.dagger_android.MainActivity_MembersInjector;
import com.plugin.gradle.lucio.dagger_android.di.module.MainModule;
import com.plugin.gradle.lucio.dagger_android.di.module.MainModule_ProvidesBoysBeanFactory;
import dagger.android.AndroidInjector;
import dagger.android.DispatchingAndroidInjector;
import dagger.android.DispatchingAndroidInjector_Factory;
import dagger.internal.Preconditions;
import java.util.Collections;
import java.util.Map;
import javax.inject.Provider;

public final class DaggerAppComponent implements AppComponent {
  private Provider<SonComponent.Builder> sonComponentBuilderProvider;

  private DaggerAppComponent(Builder builder) {
    initialize(builder);
  }

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

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

  private Map<Class<? extends Activity>, Provider<AndroidInjector.Factory<? extends Activity>>>
      getMapOfClassOfAndProviderOfFactoryOf() {
    return Collections
        .<Class<? extends Activity>, Provider<AndroidInjector.Factory<? extends Activity>>>
            singletonMap(MainActivity.class, (Provider) sonComponentBuilderProvider);
  }

  private DispatchingAndroidInjector<Activity> getDispatchingAndroidInjectorOfActivity() {
    return DispatchingAndroidInjector_Factory.newDispatchingAndroidInjector(
        getMapOfClassOfAndProviderOfFactoryOf());
  }

  private DispatchingAndroidInjector<Fragment> getDispatchingAndroidInjectorOfFragment() {
    return DispatchingAndroidInjector_Factory.newDispatchingAndroidInjector(
        Collections
            .<Class<? extends Fragment>, Provider<AndroidInjector.Factory<? extends Fragment>>>
                emptyMap());
  }

  @SuppressWarnings("unchecked")
  private void initialize(final Builder builder) {
    this.sonComponentBuilderProvider =
        new Provider<SonComponent.Builder>() {
          @Override
          public SonComponent.Builder get() {
            return new SonComponentBuilder();
          }
        };
  }

  @Override
  public void inject(App instance) {
    injectApp(instance);
  }

  private App injectApp(App instance) {
    App_MembersInjector.injectDispatchingAndroidInjector(
        instance, getDispatchingAndroidInjectorOfActivity());
    App_MembersInjector.injectFragmentSupportInjector(
        instance, getDispatchingAndroidInjectorOfFragment());
    return instance;
  }

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

    public AppComponent build() {
      return new DaggerAppComponent(this);
    }
  }

  private final class SonComponentBuilder extends SonComponent.Builder {
    private MainModule mainModule;

    private MainActivity seedInstance;

    @Override
    public SonComponent build() {
      if (mainModule == null) {
        this.mainModule = new MainModule();
      }
      if (seedInstance == null) {
        throw new IllegalStateException(MainActivity.class.getCanonicalName() + " must be set");
      }
      return new SonComponentImpl(this);
    }

    @Override
    public void seedInstance(MainActivity arg0) {
      this.seedInstance = Preconditions.checkNotNull(arg0);
    }
  }

  private final class SonComponentImpl implements SonComponent {
    private MainModule mainModule;

    private SonComponentImpl(SonComponentBuilder builder) {
      initialize(builder);
    }

    @SuppressWarnings("unchecked")
    private void initialize(final SonComponentBuilder builder) {
      this.mainModule = builder.mainModule;
    }

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

    private MainActivity injectMainActivity(MainActivity instance) {
      MainActivity_MembersInjector.injectBoysBean(
          instance, MainModule_ProvidesBoysBeanFactory.proxyProvidesBoysBean(mainModule));
      return instance;
    }
  }
}

initialize()方法初始化时创建了内部类SonComponentBuilder,提供了MainModule并创建SonComponentImpl内部类,来看下SonComponentImpl

private final class SonComponentImpl implements SonComponent {
    private MainModule mainModule;

    private SonComponentImpl(SonComponentBuilder builder) {
      initialize(builder);
    }

    @SuppressWarnings("unchecked")
    private void initialize(final SonComponentBuilder builder) {
      this.mainModule = builder.mainModule;
    }

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

    private MainActivity injectMainActivity(MainActivity instance) {
      MainActivity_MembersInjector.injectBoysBean(
          instance, MainModule_ProvidesBoysBeanFactory.proxyProvidesBoysBean(mainModule));
      return instance;
    }
  }

SonComponentImpl实现了SonComponent,而SonComponent实现了AndroidInjector<T>并传入activity,再看看AndroidInjector<T>中的 inject(T instance);什么时候调用

@Beta
public interface AndroidInjector<T> {

  /** Injects the members of {@code instance}. */
  void inject(T instance);

  /**
   * Creates {@link AndroidInjector}s for a concrete subtype of a core Android type.
   *
   * @param <T> the concrete type to be injected
   */
  interface Factory<T> {
    /**
     * Creates an {@link AndroidInjector} for {@code instance}. This should be the same instance
     * that will be passed to {@link #inject(Object)}.
     */
    AndroidInjector<T> create(T instance);
  }

  /**
   * An adapter that lets the common {@link dagger.Subcomponent.Builder} pattern implement {@link
   * Factory}.
   *
   * @param <T> the concrete type to be injected
   */
  abstract class Builder<T> implements AndroidInjector.Factory<T> {
    @Override
    public final AndroidInjector<T> create(T instance) {
      seedInstance(instance);
      return build();
    }

    /**
     * Provides {@code instance} to be used in the binding graph of the built {@link
     * AndroidInjector}. By default, this is used as a {@link BindsInstance} method, but it may be
     * overridden to provide any modules which need a reference to the activity.
     *
     * <p>This should be the same instance that will be passed to {@link #inject(Object)}.
     */
    @BindsInstance
    public abstract void seedInstance(T instance);

    /** Returns a newly-constructed {@link AndroidInjector}. */
    public abstract AndroidInjector<T> build();
  }
}

我们回头看看activity中AndroidInjection.inject(this)方法

  public static void inject(Activity activity) {
    checkNotNull(activity, "activity");
    Application application = activity.getApplication();
    if (!(application instanceof HasActivityInjector)) {
      throw new RuntimeException(
          String.format(
              "%s does not implement %s",
              application.getClass().getCanonicalName(),
              HasActivityInjector.class.getCanonicalName()));
    }

    AndroidInjector<Activity> activityInjector =
        ((HasActivityInjector) application).activityInjector();
    checkNotNull(activityInjector, "%s.activityInjector() returned null", application.getClass());

    activityInjector.inject(activity);
  }

这里通过((HasActivityInjector) application).activityInjector();取到了AndroidInjector<Activity> ,来看一下如果取到AndroidInjector,关键在于DaggerAppComponent中的inject方法,调用了injectApp

 private App injectApp(App instance) {
    App_MembersInjector.injectDispatchingAndroidInjector(
        instance, getDispatchingAndroidInjectorOfActivity());
    App_MembersInjector.injectFragmentSupportInjector(
        instance, getDispatchingAndroidInjectorOfFragment());
    return instance;
  }

看看getDispatchingAndroidInjectorOfActivity()方法,创建了DispatchingAndroidInjector

  private DispatchingAndroidInjector<Activity> getDispatchingAndroidInjectorOfActivity() {
    return DispatchingAndroidInjector_Factory.newDispatchingAndroidInjector(
        getMapOfClassOfAndProviderOfFactoryOf());
  }

 public static <T> DispatchingAndroidInjector<T> newDispatchingAndroidInjector(
      Map<Class<? extends T>, Provider<AndroidInjector.Factory<? extends T>>> injectorFactories) {
    return new DispatchingAndroidInjector<T>(injectorFactories);
  }

看一下 App_MembersInjector.injectDispatchingAndroidInjector(
instance, getDispatchingAndroidInjectorOfActivity());的代码

 public static void injectDispatchingAndroidInjector(
      App instance, DispatchingAndroidInjector<Activity> dispatchingAndroidInjector) {
    instance.dispatchingAndroidInjector = dispatchingAndroidInjector;
  }

  override fun activityInjector(): AndroidInjector<Activity>? = dispatchingAndroidInjector

这里将获取到的dispatchingAndroidInjector赋值到了App中activityInjector()方法,即获取到ActivityInjector

然后调用了activityInjector.inject(activity);方法,执行debug会执行DispatchingAndroidInjector类中inject方法

 @Override
  public void inject(T instance) {
    boolean wasInjected = maybeInject(instance);
    if (!wasInjected) {
      throw new IllegalArgumentException(errorMessageSuggestions(instance));
    }
  }

@CanIgnoreReturnValue
  public boolean maybeInject(T instance) {
    Provider<AndroidInjector.Factory<? extends T>> factoryProvider =
        injectorFactories.get(instance.getClass());
    if (factoryProvider == null) {
      return false;
    }

    @SuppressWarnings("unchecked")
    AndroidInjector.Factory<T> factory = (AndroidInjector.Factory<T>) factoryProvider.get();
    try {
      AndroidInjector<T> injector =
          checkNotNull(
              factory.create(instance), "%s.create(I) should not return null.", factory.getClass());

      injector.inject(instance);
      return true;
    } catch (ClassCastException e) {
      throw new InvalidInjectorBindingException(
          String.format(
              "%s does not implement AndroidInjector.Factory<%s>",
              factory.getClass().getCanonicalName(), instance.getClass().getCanonicalName()),
          e);
    }
  }

这里factory.create(instance)方法,会执行AndroidInjector<T>中create(),接着执行Builder中create(),执行build()和seedInstance(),此时DaggerAppComponent中内部类SonComponentBuilder才执行了build(),从而创建SonComponentImpl

interface Factory<T> {
    /**
     * Creates an {@link AndroidInjector} for {@code instance}. This should be the same instance
     * that will be passed to {@link #inject(Object)}.
     */
    AndroidInjector<T> create(T instance);
  }

abstract class Builder<T> implements AndroidInjector.Factory<T> {
    @Override
    public final AndroidInjector<T> create(T instance) {
      seedInstance(instance);
      return build();
    }

    /**
     * Provides {@code instance} to be used in the binding graph of the built {@link
     * AndroidInjector}. By default, this is used as a {@link BindsInstance} method, but it may be
     * overridden to provide any modules which need a reference to the activity.
     *
     * <p>This should be the same instance that will be passed to {@link #inject(Object)}.
     */
    @BindsInstance
    public abstract void seedInstance(T instance);

    /** Returns a newly-constructed {@link AndroidInjector}. */
    public abstract AndroidInjector<T> build();
  }

最后DispatchingAndroidInjector中的injector.inject(instance);执行
将activity传递过去,所以SonComponentImpl中实现的inject被执行了

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

    private MainActivity injectMainActivity(MainActivity instance) {
      MainActivity_MembersInjector.injectBoysBean(
          instance, MainModule_ProvidesBoysBeanFactory.proxyProvidesBoysBean(mainModule));
      return instance;
    }

由此将boysBean的依赖传递到MainAcitivity

9,简化

采用ContributesAndroidInjector注解

//@Module(subcomponents = [SonComponent::class])
@Module()
abstract class ActivityModuleBuilder {

//    @Binds
//    @IntoMap
//    @ActivityKey(MainActivity::class)
//    internal abstract fun bindYourActivityInjectorFactory(builder: SonComponent.Builder): AndroidInjector.Factory<out Activity>

    @ContributesAndroidInjector(modules = [(MainModule::class)])
    internal abstract fun bindMainActivity(): MainActivity
}

来看一下采用该注解之后的变化,会生成ActivityModuleBuilder_BindMainActivity类,生成的代码和之前使用Subcomponent形式一模一样,不再多做讲解

@Module(
  subcomponents = ActivityModuleBuilder_BindMainActivity$app_debug.MainActivitySubcomponent.class
)
public abstract class ActivityModuleBuilder_BindMainActivity$app_debug {
  private ActivityModuleBuilder_BindMainActivity$app_debug() {}

  @Binds
  @IntoMap
  @ActivityKey(MainActivity.class)
  abstract AndroidInjector.Factory<? extends Activity> bindAndroidInjectorFactory(
      MainActivitySubcomponent.Builder builder);

  @Subcomponent(modules = MainModule.class)
  public interface MainActivitySubcomponent extends AndroidInjector<MainActivity> {
    @Subcomponent.Builder
    abstract class Builder extends AndroidInjector.Builder<MainActivity> {}
  }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容