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,注入方式(構(gòu)造方式注入和module注入)

  • 采用構(gòu)造方法注入,構(gòu)造方法上加@Inject,并定義帶有@Component注解的接口

在Dagger 2中,使用javax.inject.Inject注解來標(biāo)識需要依賴注入的構(gòu)造函數(shù)和字段,以滿足Dagger構(gòu)造應(yīng)用應(yīng)用程序類的實(shí)例并滿足其依賴性。
@Inject有兩項(xiàng)職責(zé):
注解構(gòu)造函數(shù):通過標(biāo)記構(gòu)造函數(shù),告訴Dagger 2可以創(chuàng)建該類的實(shí)例(Dagger2通過Inject標(biāo)記可以在需要這個類實(shí)例的時候來找到這個構(gòu)造函數(shù)并把相關(guān)實(shí)例new出來)從而提供依賴關(guān)系。
使用@Component作為依賴注入橋梁,@Component一般用來注解接口,被注解的接口在編譯時會產(chǎn)生相應(yīng)的實(shí)例,作為提供依賴和所需依賴之間的橋梁,把相關(guān)依賴注入到其中

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)
}
/**
 * 構(gòu)造方式注入
 */
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 = "學(xué)生: " + studentBean.name + studentBean.num
        text2.text = "老師: " + teacherBean.studentBean.name + teacherBean.studentBean.num
    }
}

運(yùn)行之后如下:


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提供依賴關(guān)系。
之前已經(jīng)提到了,@Inject可以提供依賴關(guān)系,但是其不是萬能的。如果我們所需要的提供的構(gòu)造函數(shù)沒有使用@Inject注解,那么Module類可以在不修改構(gòu)造函數(shù)的情況下,通過provide提供依賴關(guān)系。即使是可以用@Inject注解的,依然可以通過Module提供依賴關(guān)系。

這里,我們需要明確的一個概念是@Module注解的類,是向Dagger提供依賴關(guān)系

  • 定義module類,通過provide提供實(shí)例
@Module
class MainModule {

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

    @Provides
    fun provideTeacherBean(studentBean: StudentBean): TeacherBean = TeacherBean(studentBean)
}
  • 這里因?yàn)槭褂胢odule,Activity中Component注入的方式有所改變,需要使用DaggerMainCompoment中Builder提供module并創(chuàng)建,如下
/**
 * 通過module進(jìn)行注入
 */
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 = "學(xué)生: " + studentBean.name + studentBean.num
        text2.text = "老師: " + teacherBean.studentBean.name + teacherBean.studentBean.num

    }
}

最終結(jié)果展示如下


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;
    }
  }

通過創(chuàng)建Builder,提供了mainModule的實(shí)例,并傳到MainCompoment

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

通過proxyProvideStudentBean方法獲取StudentBean實(shí)例,代碼如下:

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

通過MainModule.取到了該類中提供的StudentBean實(shí)例,最后一步往下看

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

injectStudentBean方法將獲取到的studentBean賦值給了Test2Activity

  • 再來看一下顯示提供依賴的實(shí)現(xiàn),增加provideStudentBean方法
@Component(modules = [MainModule::class])
interface MainCompoment {

    fun inject(test1Activity: Test1Activity)

    fun inject(test2Activity: Test2Activity)

    fun provideStudentBean(): StudentBean
}

如下調(diào)用

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

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

此方法provideStudentBean,最終會在DaggerMainCompoment進(jìn)行實(shí)現(xiàn),最終還是調(diào)用到MainModule中提供的實(shí)例

 @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的“依賴迷失”,無法確定提供哪個依賴
    可通過自定義注解進(jìn)行區(qū)分,如下不做詳解
@Module()
public class FruitModule {

    //使用限定符來區(qū)別使用哪個構(gòu)造函數(shù)返回對象
    @Type("color")
    @Provides
    public AppleBean provideColorApple() {
        return new AppleBean("red");
    }

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

4,@Scope作用域

作用域的理解是變量的作用范圍,因此,出現(xiàn)了全局變量和局部變量之分
同vue中css使用scope,表示css只在當(dāng)前頁面生效;所以scope如同設(shè)定提供依賴的聲明周期一樣.如定義的@AppScope在App進(jìn)行build,最終生命周期是整個app,如定義的@ActivityScope是在Activity中build,那么生命周期同activity

如果使用了@Scope注解了該類,注入器會緩存第一次創(chuàng)建的實(shí)例,然后每次重復(fù)注入緩存的實(shí)例,而不會再創(chuàng)建新的實(shí)例

接下來結(jié)合代碼實(shí)例講解,只有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進(jìn)行緩存了,我們來看看DaggerMainCompoment生成的代碼的區(qū)別

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

由BoysBean類生成的factory代碼開始使用,通過create創(chuàng)建了MainModule_ProvideBoysBeanFactory,并通過get()提供BoysBean實(shí)例

 @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的區(qū)別

 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)重新創(chuàng)建,由此可見BoysBean的實(shí)例隨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
    }
}

生成代碼同上,不做分析,測試結(jié)果如下


image.png

5,多個元素綁定并注入到Map

Dagger不僅可以將綁定的多個元素依賴注入到Set,還可以將綁定的多個元素依賴注入到Map。與依賴注入Set不同的是,依賴注入Map時,必須在編譯時指定Map的Key,那么Dagger向MapMap注入相應(yīng)的元素。
對于向Map提供元素的@Provides方法,需要使用@IntoMap,同時指定該元素的Key(例如@StringKey(“foo”)、@ClassKey(Thing.class))。

  • 我們先以StringKey、ClassKey注解為例注入Map:
    @Provides
    @IntoMap // 指定該@Provides方法向Map提供元素
    @StringKey("A") // 指定該元素在Map中所對應(yīng)的的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

    }
}

結(jié)果如下:


image.png

6,自定義Key

在注釋類型中聲明的方法的返回類型,如果不滿足指定的返回類型,那么編譯時會報(bào)錯:
基本數(shù)據(jù)類型
String
Class
枚舉類型
注解類型
以上數(shù)據(jù)類型的數(shù)組

@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

結(jié)果如下


image.png

7,Component依賴關(guān)系

在使用Dagger 2開發(fā)時,一般都是在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(子組件)和組件依賴最大的不同是當(dāng)你接入父組件的時候,你可以訪問它所有模塊的所有對象而無需顯示聲明依賴父組件,而組件依賴必須顯示提供依賴,后面做詳解

  • Subcomponent的介紹

對于繼承,大家應(yīng)該都不陌生,其實(shí)就是子類繼承父類,子類自動獲取了的父類的屬性和行為。我覺得我們也可以這么認(rèn)為子組件。子組件是繼承和擴(kuò)展父組件的對象的組件

  • 添加子組件

聲明子組件,與普通組件聲明類似,可以通過編寫一個抽象類或接口來創(chuàng)建一個子組件,該類或接口聲明了返回應(yīng)用程序相關(guān)的類型的抽象方法??梢允褂聾Component,也可以使用@Subcomponent注解,這個沒有一定的強(qiáng)制性。

與@Component注解不同的是,使用@Subcomponent注解子組件,必須聲明其xxComponent.Builder,否則編譯時,會報(bào)錯。

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

    AppleBean supplyApple();

    @Subcomponent.Builder
    interface Builder{
        Builder appleModule(AppleModule module);
        AppleSubcomponent build();
    }
}
通過@Component的dependencies屬性依賴父組件

注意:
子類的作用域和父類的不能一樣,要不然會報(bào)以下錯誤
SecondComponent depends on scoped components in a non-hierarchical scope ordering:

依賴Component(OrangeComponent) 僅繼承 被依賴Component(FruitComponent) 中顯示提供的依賴。如果被依賴Component(FruitComponent)必須提供依賴注入的對象,也就是將對象實(shí)例暴露出來。否則,在子組件,也就是依賴Component(OrangeComponent)中,無法使用@Inject注入被依賴的Component(AppComponent)中的對象,此時編譯器會報(bào)錯,提示依賴注入的Xx實(shí)例沒有提供@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
    }
}

結(jié)果如下


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;
  }
  • 測試一下不顯示的提供依賴會有什么結(jié)果, 編譯時DeComponent會報(bào)錯
/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一樣,只能標(biāo)注接口或抽象類,與依賴關(guān)系一樣,SubComponent 與 parent Component 的 Scope 不能相同,只是 SubComponent 表明它是繼承擴(kuò)展某 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  // 用來創(chuàng)建 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 = "學(xué)生: " + studentBean.name + studentBean.num
        text2.text = "老師: " + teacherBean.studentBean.name + teacherBean.studentBean.num

    }
}

結(jié)果如下


image.png

我們來看一下生成的代碼,如果取到parent Component的依賴

  • 首先通過sonComponent創(chuàng)建SonComponentBuilder
@Override
  public SonComponent.Builder sonComponent() {
    return new SonComponentBuilder();
  }
  • 通過SonComponentBuilder中build創(chuàng)建SonComponentImpl,再調(diào)用inject方法,
    到這里我們就發(fā)現(xiàn), SonComponentImpl是MainComponent的內(nèi)部類,自然可以獲取到外部類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

結(jié)果如下


image.png

看看生成的代碼, build中創(chuàng)建了AppleModule, injectAppleBean則進(jìn)行了注入

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

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

8,完美擴(kuò)展庫-dagger.android

  • Dagger的使用流程

1,在ApplicationComponent中注入AndroidInjectionModule,如果項(xiàng)目中用到v4包的Fragment,還需注入AndroidSupportInjectionModule.建議把兩個Module都注入XxComponent中

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

2,創(chuàng)建子組件 - @Subcomponent,其繼承自AndroidInjector<T>,而T就是step2創(chuàng)建的Android庫的類型

@Subcomponent(modules = [MainModule::class])    //這里需要MainModule,否則會關(guān)聯(lián)不上
interface SonComponent : AndroidInjector<MainActivity> {

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

3,創(chuàng)建Module,其subcomponents屬性值就是step3創(chuàng)建的子組件。在其內(nèi)必須聲明一個抽象方法,該抽象方法返回AndroidInjector.Factory<?>實(shí)例,而其參數(shù)為step1創(chuàng)建的XxSubcomponent.Builder實(shí)例。

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

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

4,將創(chuàng)建的Module注入到ApplicationComponent中,即把其添加至ApplicationComponent的modules屬性列表,即添加ActivityBuilder

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

5,創(chuàng)建Application。實(shí)現(xiàn)HasActivityInjector, HasSupportFragmentInjector支持activity和fragment的注解。

class App : Application(), HasActivityInjector, HasSupportFragmentInjector {

    //依賴注入的核心原則:一個類不應(yīng)該知道如何實(shí)現(xiàn)依賴注入。
    @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,否則會關(guān)聯(lián)不上
interface SonComponent : AndroidInjector<MainActivity> {

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

7,創(chuàng)建Android庫的核心類,需要注意的就是:AndroidInjection.inject(T)方法的調(diào)用位置,即可展示出來

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()方法初始化時創(chuàng)建了內(nèi)部類SonComponentBuilder,提供了MainModule并創(chuàng)建SonComponentImpl內(nèi)部類,來看下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實(shí)現(xiàn)了SonComponent,而SonComponent實(shí)現(xiàn)了AndroidInjector<T>并傳入activity,再看看AndroidInjector<T>中的 inject(T instance);什么時候調(diào)用

@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,關(guān)鍵在于DaggerAppComponent中的inject方法,調(diào)用了injectApp

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

看看getDispatchingAndroidInjectorOfActivity()方法,創(chuàng)建了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

然后調(diào)用了activityInjector.inject(activity);方法,執(zhí)行debug會執(zhí)行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)方法,會執(zhí)行AndroidInjector<T>中create(),接著執(zhí)行Builder中create(),執(zhí)行build()和seedInstance(),此時DaggerAppComponent中內(nèi)部類SonComponentBuilder才執(zhí)行了build(),從而創(chuàng)建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);執(zhí)行
將activity傳遞過去,所以SonComponentImpl中實(shí)現(xiàn)的inject被執(zhí)行了

 @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> {}
  }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容