Dagger2 在 Kotlin 中的使用

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
  1. 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.

  1. NetModule
    在这里只是简单的去 provide 一个 OkHttpClient 如果需要提供其他依赖的话同样的方式可以提供,如果需要提供不一样的 OkHttpClient 的话可以通过 Named(“XXX”) 去提供,注意需要将 @Singleton 去掉,有多个当然不可能是 Singleton 啦~ 在 Module 类的前面需要加入 @Module 注解才可以被反射识别到。
@Module
class NetModule{

    @Singleton
    @Provides
    fun provideOkHttpClient(): OkHttpClient{
        return OkHttpClient().newBuilder().build()
    }
}
  1. 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())
    }
}

常见问题

  1. 注入的时候不小心形成了一个注入的环一般会报出这么一个错误
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 的依赖,那么两者在相互引用在互相等待,所以就形成了一个闭环。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值