• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

daggerandroid多模块项目实现一

android 搞代码 3年前 (2022-03-02) 16次浏览 已收录 0个评论

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

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

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

<code class="kotlin">NewsComponentHolder.newsComponent.inject(this)
UserComponentHolder.userComponent.inject(this)

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

先看一般多模块我的项目

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

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

<code class="kotlin">Map<Class<?>, Provider<AndroidInjector.Factory<?>>> injectorFactoriesWithClassKeys
Map<String, Provider<AndroidInjector.Factory<?>>> injectorFactoriesWithStringKeys

这两个Map定义在AndroidInjectionModule中

<code class="java">@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中去

<code class="kotlin">@Module(includes = [AndroidInjectionModule::class])
abstract class NewsBindModule {
    @ContributesAndroidInjector
    abstract fun newsActivity(): NewsActivity
}

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

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

<code class="kotlin">@NewsScope
@Subcomponent(modules = [NewsModule::class, NewsBindModule::class])
interface NewsComponent {

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

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

<code class="kotlin">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好了)

<code class="kotlin">@NewsScope
@Subcomponent(modules = [NewsModule::class, NewsBindModule::class])
interface NewsComponent {

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

而后在AppApplication中注入

<code class="kotlin">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里

<code class="kotlin">open class BaseActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        AndroidInjection.inject(this)
        super.onCreate(savedInstanceState)
    }
}

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

<code class="kotlin">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

<code class="kotlin">class BaseDispatchingInjector  {
    @Inject
    lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Any>
}

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

<code class="kotlin">@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)
}

这样注入

<code class="kotlin">val userDispatchingInjector = BaseDispatchingInjector()
UserComponentHolder.userComponent.inject(userDispatchingInjector)
val newsDispatchingInjector = BaseDispatchingInjector()
NewsComponentHolder.newsComponent.inject(newsDispatchingInjector)

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

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

<code class="kotlin">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最初实现

<code class="kotlin">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
    }
}

代码地址


搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:daggerandroid多模块项目实现一

喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址