1.背景
网上已经有很多大牛介绍过Dagger的原理以及使用方法了,说实在的,我在没有阅读代码的情况下,看大牛们的分析有一种尿急的感觉。于是我就去阅读代码了,天啊,我读不进去。别人写了教程读不懂,源码也读不懂,那怎么办呢。有点儿怀疑人生了,怎么别人懂得那么透彻,我就是不懂啊啊啊!
我写这篇文章的目的是不读源码,不分析原理,用的时候知道在哪里添加对应的方法。建议在读这篇前,先按照网上其他人的博客例子敲下。
2.gradle
- 在gradle里添加dagger
compile 'com.google.dagger:dagger:2.10'
kapt 'com.google.dagger:dagger-compiler:2.10'
- 在gradle的dependencies上面添加apt,这个可能是由于dagger会生成很多中间类所以要用apt,这个不用多管,知道怎么用就行了
kapt {
generateStubs = true
}
3.四个注解
- @Inject注解
- @Module注解
- @Component注解
- @Provides
这么一看好牛叉啊,用四个注解就能完成依赖注入功能,你们是不是有什么特异功能?下面就说说这些注解到底是什么吧!
- @Inject
- 你想让谁自动注入就在这个变量前加上这个注解,这里的变量指的是类的变量,方法里面的那种局部变量就不要想了。
- 2.找到你加注解的这个变量对应的类,然后在构造方法里也加上这个注解。
- 3.例子: class MainActivity{
@Inject
lateinit var mPresenter:MyPresenter
}
class MyPresenter @Inject constructor(var name:String){
}
- @Module和@Provides
- 新建一个类,给这个类加上@Module注解。这个里面加什么方法呢?加第二个Inject注解构造方法里的参数,这个方法返回值是假Inject注解的构造方法里的参数类型,例如上面的var name:String,就加个方法返回值是String类型,然后给方法加个@Provides注解。
- 例子: @Module
class ActivityModule{
@Provides
fun provideString():String = "test_dagger"
}
- @Component
- 新建一个接口类,用@Component标注
- 添加个方法,名字随便取,参数是Inject注解里讲的MainActivity
- @Component(modules = arrayOf(ActivityModule::class))
interface ActivityComponent{
inject(mA:MainActivity)
}
4.导入
前面倒腾了这么多,运行起来还是不行,别着急,这一步会把上面生成的一些中间类(是这么叫吗?就是生成在app\build\generated\source\kapt\debug\包名 下面的那些)导入
DaggerActivityComponent.builder()
.activityModule(ActivityModule())
.build()
.inject(this)
5.中间类
- ActivityModule_ProvideStringFactory
这个类是根据ActivityModule类生成的,有@Provide标注的方法都会生成一个这样的类。如:在ActivityModule中添加如下代码会自动生成ActivityModule_ProvideIntFactory。这些ActivityModule开头的Factory类持有ActivityModule的引用,在get()方法中调用对应的方法。如,ActivityModule_ProvideStringFactory的get()方法返回的是activityModule.provideString();而ActivityModule_ProvideIntFactory的get()方法返回的是activityModule.provideInt()。
@Provides
fun provideInt():Int = 18
- 2.MyPresenter_Factory
这个类就是MainActivity中想自动导入依赖的类生成的中间类。还得看下MyPresenter带Inject注解的构造方法是什么类型,这里是String类型。那这个MyPresenter_Factory就持有ActivityModule_ProvideStringFactory类,get()方法返回的是new MyPresenter(ActivityModule_ProvideStringFactory.get())。这里是不是有点儿晕啊?MyPresenter的构造方法需要String类型------>ActivityModule_ProvideStringFactory类,因为只有这个类才能给它String,别人不给。咦,喂喂喂,等等,如果ActivityModule里面有两个返回值是String类型的方法,那不是就生成两个provideStringFactory类了吗?那要谁的值?别担心这样会编译报错。啊,原来这样。- 3.MainActivity_MembersInjector
这个类的作用是MainActivity想自动导入几个变量,这个类就持有哪几个变量对应的Factory对象,如MyPresenter_Factory。然后,调用DaggerActivityComponent的inject方法时,由于传递了MainActivity对象,inject方法就是给mPresenter赋值为MyPresenter_Factory对象的get()方法返回值。所以,你想要自动注入的变量,不能声明为private。要不,它怎么赋值啊。
6.冲突
上面说了ActivityModule不能有两个加@Provides注解返回值类型一样。有时候就是有这种需求咋整?这就用到了@Qualifier注解。表达能力太弱了,直接上代码。
定义MyString注解
@Qualifier
@MustBeDocumented
@Retention(AnnotationRetention.RUNTIME)
annotation class MyString
定义HisString注解
@Qualifier
@MustBeDocumented
@Retention(AnnotationRetention.RUNTIME)
annotation class HisString
MyPresenter类
class MyPresenter @Inject constructor(@MyString val name:String) {
}
class HisPresenter @Inject constructor(@HisString val name:String) {
}
ActivityModule类
@Provides
@MyString
fun provideString():String =
"ActivityModule"
@Provides
@HisString
fun provideHisString():String =
"HisModule"