1,概述
在Dagger 2官方文档中,有这么一句话“A fast dependency injector for Android and Java.”,翻译过来的意思就是:适用于Android和Java的快速依赖注入。
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
}
}
运行之后如下:
看下变成生成的代码:
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
}
}
最终结果展示如下
- 那么我们来看看编译生成的代码,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
}
}
生成代码同上,不做分析,测试结果如下
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
}
}
结果如下:
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
结果如下
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
}
}
结果如下
我们来看一下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
}
}
结果如下
我们来看一下生成的代码,如果取到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
结果如下
看看生成的代码, 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> {}
}
}