本文适合有必定的Dagger2使用基础的同窗java
上一篇:Dagger2多模块项目Component组织方式选择(二)
下一篇:dagger.android多模块项目实现(二)android
前两篇文章咱们讲了两种多模块项目怎么使用Dagger2。
发如今每一个Activity的onCreate中都须要调一个inject方法git
NewsComponentHolder.newsComponent.inject(this) UserComponentHolder.userComponent.inject(this)
其实还能够用dagger2专给android使用的dagger.android来简化这种操做。 github
先看普通多模块项目segmentfault
咱们在Dagger2多模块项目Component组织方式选择(一)的基础上改造实现app
dagger.android的核心思想是在每一个Component收集两个Mapide
Map<Class<?>, Provider<AndroidInjector.Factory<?>>> injectorFactoriesWithClassKeys Map<String, Provider<AndroidInjector.Factory<?>>> injectorFactoriesWithStringKeys
这两个Map定义在AndroidInjectionModule中this
@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中spa
怎么收集呢code
首先定义一个 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 } }