Dagger2 的基础知识和概念并不会在此文中过多描述,可以查阅 https://www.jianshu.com/p/c985e3f262f2
依赖
版本比较旧,可自行更新到最新版本
implementation 'com.google.dagger:dagger:2.21'
implementation 'com.google.dagger:dagger-android-support:2.21'
kapt 'com.google.dagger:dagger-android-processor:2.21'
kapt 'com.google.dagger:dagger-compiler:2.21'
implementation 'com.google.dagger:dagger-android:2.21'
注意:kapt 需要在 module 的 build.gradle 中加入
apply plugin: ‘kotlin-kapt’
代码
Component
可以将起理解为一个注射器,而里面包含着各种药物(各种 module),将药物(依赖提供者)注入到人体(依赖需求者),从而实现了依赖注入的过程。
@Singleton
@Component(
modules = [
AndroidSupportInjectionModule::class,
NetModule::class,
ActivityBuilder::class
]
)
interface AppComponent {
@Component.Builder
interface Builder {
@BindsInstance
fun application(application: MyApplication): Builder
fun build(): AppComponent
}
fun inject(application: MyApplication)
}
其中 AndroidSupportInjectionModule,NetModule 等 Module 都是一个一个的依赖提供者,里面提供了各种各样的依赖
Application
class MyApplication : Application(), HasActivityInjector, HasSupportFragmentInjector {
private lateinit var appComponent: AppComponent
override fun onCreate() {
super.onCreate()
initDagger()
}
private fun initDagger() {
appComponent = DaggerAppComponent.builder()
.application(this)
.build()
appComponent.inject(this)
}
@Inject
internal lateinit var activityDispatchingAndroidInjectot: DispatchingAndroidInjector<Activity>
@Inject
internal lateinit var fragmentDispatchingAndroidInjectot: DispatchingAndroidInjector<Fragment>
override fun supportFragmentInjector(): AndroidInjector<Fragment> {
return fragmentDispatchingAndroidInjectot
}
override fun activityInjector(): AndroidInjector<Activity> {
return activityDispatchingAndroidInjectot
}
}
HasActivityInjector,HasSupportFragmentInjector 接口分别起到的作用是:注入 Activity 和 Fragment,不然单纯只是通过 module 去 bind Activity 的话是无法去提供对应的 Activity 或者 Fragment 的依赖的。下面在讲到 Activity 会详细讲到。
注意:记得将这个 Application 注册到 AndroidManifest.xml 中
Module
- AndroidSupportInjectionModule
这个是 Dagger2 默认需要提供的一个 Module 关于它的解释是这样的
This module no longer provides any value beyond what is provided in {@link * AndroidInjectionModule} and is just an alias. It will be removed in a future release.
- NetModule
在这里只是简单的去 provide 一个 OkHttpClient 如果需要提供其他依赖的话同样的方式可以提供,如果需要提供不一样的 OkHttpClient 的话可以通过 Named(“XXX”) 去提供,注意需要将 @Singleton 去掉,有多个当然不可能是 Singleton 啦~ 在 Module 类的前面需要加入 @Module 注解才可以被反射识别到。
@Module
class NetModule{
@Singleton
@Provides
fun provideOkHttpClient(): OkHttpClient{
return OkHttpClient().newBuilder().build()
}
}
- ActivityBuilder
这个比较特殊,是用来提供一些 Activity 和 Fragment 的,但是是需要 Application 去实现 HasActivityInjector, HasSupportFragmentInjector 这两个借口,而且实现类也不能返回空的 AndroidInjector, 我们可以看到源码
public static void inject(Activity activity) {
checkNotNull(activity, "activity");
Application application = activity.getApplication();
// 这个会去判断是否有去实现 HasActivityInjector 接口,Fragment 也同理
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);
}
ok,接下来说一下 ActivityBuilder 怎么去 bindActivity
@Module
interface ActivityBuilder {
// 必须使用这个注解,返回我们想要提供的类
@ContributesAndroidInjector
fun bindMainActivity(): MainActivity
}
在 Activity / Fragment的使用
class MainActivity : AppCompatActivity() {
@Inject
lateinit var okHttpClient: OkHttpClient
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// inject
AndroidInjection.inject(this)
setContentView(R.layout.activity_main)
// verify okHttpClient is inject
println(okHttpClient.toString())
}
}
常见问题
- 注入的时候不小心形成了一个注入的环一般会报出这么一个错误
e: E:\StudyProject\KotlinCoroutines\app\build\tmp\kapt3\stubs\debug\com\example\kotlincoroutines\di\AppComponent.java:8: ����: [Dagger/DependencyCycle] Found a dependency cycle:
public abstract interface AppComponent {
^
okhttp3.OkHttpClient is injected at
com.example.kotlincoroutines.di.NetModule.provideTestDemo(okHttpClient)
com.example.kotlincoroutines.ui.Test is injected at
com.example.kotlincoroutines.di.NetModule.provideOkHttpClient(test)
okhttp3.OkHttpClient is injected at
com.example.kotlincoroutines.ui.MainActivity.okHttpClient
com.example.kotlincoroutines.ui.MainActivity is injected at
dagger.android.AndroidInjector.inject(T) [com.example.kotlincoroutines.di.AppComponent �� com.example.kotlincoroutines.di.ActivityBuilder_BindMainActivity.MainActivitySubcomponent]
Found a dependency cycle 主要还是这一句,然后下面会提示你造成环的原因,你需要自己去发现在哪里形成了一个闭环,下面通过一个例子讲解一下
@Module
class NetModule{
@Singleton
@Provides
fun provideOkHttpClient(test: Test): OkHttpClient{
return OkHttpClient().newBuilder().build()
}
@Singleton
@Provides
fun provideTestDemo(okHttpClient: OkHttpClient): Test{
return Test()
}
}
看上面代码形成的闭环就很容易:TestDemo 的依赖需要提供 OkHttpClient 的依赖,而 OkHttpClient 需要 Test 的依赖,那么两者在相互引用在互相等待,所以就形成了一个闭环。