本文適合有必定的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 } }