乐趣区

关于android:daggerandroid多模块项目实现一

本文适宜有肯定的 Dagger2 应用根底的同学

上一篇:Dagger2 多模块我的项目 Component 组织形式抉择 (二)
下一篇:[dagger.android 多模块我的项目实现(二)]()

前两篇文章咱们讲了两种多模块我的项目怎么应用 Dagger2。
发现在每个 Activity 的 onCreate 中都须要调一个 inject 办法

NewsComponentHolder.newsComponent.inject(this)
UserComponentHolder.userComponent.inject(this)

其实还能够用 dagger2 专给 android 应用的 dagger.android 来简化这种操作。

先看一般多模块我的项目

咱们在 Dagger2 多模块我的项目 Component 组织形式抉择 (一) 的根底上革新实现

dagger.android 的核心思想是在每个 Component 收集两个 Map

Map<Class<?>, Provider<AndroidInjector.Factory<?>>> injectorFactoriesWithClassKeys
Map<String, Provider<AndroidInjector.Factory<?>>> injectorFactoriesWithStringKeys

这两个 Map 定义在 AndroidInjectionModule 中

@Beta
@Module
public abstract class AndroidInjectionModule {
  @Multibinds
  abstract Map<Class<?>, AndroidInjector.Factory<?>> classKeyedInjectorFactories();

  @Multibinds
  abstract Map<String, AndroidInjector.Factory<?>> stringKeyedInjectorFactories();

  private AndroidInjectionModule() {}
}

dagger.android 会把把收集到的这两个 Map 注入到 DispatchingAndroidInjector 中,dagger.android 就是通过这个 DispatchingAndroidInjector 注入到 Activity,Fragment 中

怎么收集呢

首先定义一个 xxxBindModule,将要注入的 Activity,fragment 用 @ContributesAndroidInjector 注解

dagger.android 会把这些收集到后面的 Map 中去

@Module(includes = [AndroidInjectionModule::class])
abstract class NewsBindModule {
    @ContributesAndroidInjector
    abstract fun newsActivity(): NewsActivity}

而后相应的 Component 的 modules 加上 xxxBindModule,

去掉 inject(XXXActivity)这样的一大堆申明办法, 洁净多了

@NewsScope
@Subcomponent(modules = [NewsModule::class, NewsBindModule::class])
interface NewsComponent {

    @Subcomponent.Factory
    interface Factory {fun create(): NewsComponent
    }
}

之后依照 dagger.android 用法要让 Application 实现 HasAndroidInjector 接口,并注入 dispatchingAndroidInjector 实例

class AppApplication : BaseApplication(), NewsComponentProvider, UserComponentProvider, HasAndroidInjector {
      
      @Inject
    lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Any>
      
    lateinit var appComponent: AppComponent
    override fun onCreate() {super.onCreate()
        appComponent = DaggerAppComponent.factory().create(this)
    }

    override fun provideNewsComponent(): NewsComponent {return appComponent.newsComponentFactory().create()}

    override fun provideUserComponent(): UserComponent {return appComponent.userComponentFactory().create()}
  
    override fun androidInjector(): AndroidInjector<Any> {return dispatchingAndroidInjector}
}

再在 Component 加上一个注入到下面 Appliction 的办法(因为 news 模块拿不到 AppApplication 的援用,间接注入到 Any 好了)

@NewsScope
@Subcomponent(modules = [NewsModule::class, NewsBindModule::class])
interface NewsComponent {

    @Subcomponent.Factory
    interface Factory {fun create(): NewsComponent
    }
  
    fun inject(any: Any)
}

而后在 AppApplication 中注入

class AppApplication : BaseApplication(), NewsComponentProvider, UserComponentProvider {
      
      @Inject
    lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Any>
      
    lateinit var appComponent: AppComponent
    override fun onCreate() {super.onCreate()
        appComponent = DaggerAppComponent.factory().create(this)
          NewsComponentHolder.newsComponent.inject(this)
    }

    override fun provideNewsComponent(): NewsComponent {return appComponent.newsComponentFactory().create()}

    override fun provideUserComponent(): UserComponent {return appComponent.userComponentFactory().create()}
  
    override fun androidInjector(): AndroidInjector<Any> {return dispatchingAndroidInjector}
}

最初在 Activity,fragment 的 onCreate 办法中退出 AndroidInjection.inject(this), 留神要放在 super.onCreate(savedInstanceState)后面, 咱们把这一步放在 BaseActivity,BaseFragment 里

open class BaseActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {AndroidInjection.inject(this)
        super.onCreate(savedInstanceState)
    }
}

而后 Activity 只有继承 BaseActivity 就能够了,不须要写任何注入代码了,像平时应用一样了,想要注入对象的变量加 @Inject 就能够了

class NewsActivity : BaseActivity() {

    @Inject
    lateinit var set: Set<String>

    override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_news)
        text.text = set.toString()}
}

这种写法对于单模块我的项目没有问题,然而对多模块我的项目来说这有问题了,下面咱们只注入了 news 模块的,user 模块的没有。咱们有多个 Component, 然而这里只有一个 dispatchingAndroidInjector,你用哪个 Component 注入都不全,前面注入的会笼罩后面注入的。所以这里要革新下

从后面咱们晓得一个 Component 最终生成一个 DispatchingAndroidInjector,多个 Component 咱们把它们都收集起来

咱们先定义一个 BaseDispatchingInjector, 它相当于后面的 AppApplication, 接管一个 Component 注入的 DispatchingAndroidInjector

class BaseDispatchingInjector  {
    @Inject
    lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Any>
}

而后把每个 Component 里的 inject(any: Any)改成 inject(baseDispatchingInjector: BaseDispatchingInjector)

@NewsScope
@Subcomponent(modules = [NewsModule::class, NewsBindModule::class])
interface NewsComponent {

    @Subcomponent.Factory
    interface Factory {fun create(): NewsComponent
    }

    fun inject(baseDispatchingInjector: BaseDispatchingInjector)
}
@UserScope
@Subcomponent(modules = [UserModule::class, UserBindModule::class])
interface UserComponent {
    @Subcomponent.Factory
    interface Factory {fun create(): UserComponent
    }

    fun inject(baseDispatchingInjector: BaseDispatchingInjector)
}

这样注入

val userDispatchingInjector = BaseDispatchingInjector()
UserComponentHolder.userComponent.inject(userDispatchingInjector)
val newsDispatchingInjector = BaseDispatchingInjector()
NewsComponentHolder.newsComponent.inject(newsDispatchingInjector)

这样咱们每个模块都失去一个 BaseDispatchingInjector, 并且外面每个 Activity,Fragment 对应的 Map 都注入好了

而后就要定义一个 MultiModuleAndroidInjector 把每个模块的 BaseDispatchingInjector 整合到一起成为一个独自的 AndroidInjector

class MultiModuleAndroidInjector : AndroidInjector<Any> {private val injectors = mutableListOf<BaseDispatchingInjector>()

    fun addInjector(injector: HasDispatchingInjector) {injectors.add(injector)
    }

    override fun inject(instance: Any) {val wasInjected = injectors.any { it.dispatchingAndroidInjector.maybeInject(instance) }
        if (!wasInjected) {throw IllegalArgumentException("injection failed")
        }
    }
}

这个 MultiModuleAndroidInjector 在注入的时候会每个 BaseDispatchingInjector 都去尝试看能不能注入,这样就把所有 Component 的注解都遍历了

看 AppApplication 最初实现

class AppApplication : BaseApplication(), NewsComponentProvider, UserComponentProvider,
    HasAndroidInjector {

    lateinit var appComponent: AppComponent

    private val multiModuleAndroidInjector = MultiModuleAndroidInjector()

    override fun onCreate() {super.onCreate()
        appComponent = DaggerAppComponent.factory().create(this)
        val userDispatchingInjector = BaseDispatchingInjector()
        UserComponentHolder.userComponent.inject(userDispatchingInjector)
        multiModuleAndroidInjector.addInjector(userDispatchingInjector)
        val newsDispatchingInjector = BaseDispatchingInjector()
        NewsComponentHolder.newsComponent.inject(newsDispatchingInjector)
        multiModuleAndroidInjector.addInjector(newsDispatchingInjector)
    }

    override fun provideNewsComponent(): NewsComponent {return appComponent.newsComponentFactory().create()}

    override fun provideUserComponent(): UserComponent {return appComponent.userComponentFactory().create()}

    override fun androidInjector(): AndroidInjector<Any> {return multiModuleAndroidInjector}
}

代码地址

退出移动版