android - 如何解决不同范围的绑定(bind)?

标签 android kotlin dagger-2

我有一个模型(AModel),我想用作单例。我创建了一个名为 @ApplicationScope 的自定义范围,以便将它用于我只需要一次的每个类。所以 AppComponent 和 AModel 共享这个 @ApplicationScope。我有一些 fragment (ConfirmationFragment),我想同时使用 AModel 和 BModel。 BModel 具有不同的范围,因为我想在 3 个 fragment 中使用它,但 Amodel 到处都需要。

访问 AModel 和 BModel 的想法是让 ConfirmationComponent 依赖于 AModel 已经可用的 AppComponent。这样,如果我将 ConfirmationComponent 注入(inject) ConfirmationFragment,我也可以使用 AModel。
但我收到以下错误:[Dagger/IncompatiblyScopedBindings] ConfirmationComponent scoped with @ConfirmationScope may not reference bindings with different scopes:
当从 ConfirmationFragment 中注释掉注入(inject) AModel 时构建成功,但在没有注释时失败。我也需要那个 fragment 中的 AModel。

我该如何解决这个问题?
(以防它很重要:我只使用一个 Activity ,并让 Android 导航处理 fragment 。)

open class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        val appComponent = initializeComponent()
    }

    val appComponent: AppComponent by lazy {
        initializeComponent()
    }

    val confirmationComponent: ConfirmationComponent by lazy {
        initializeConfirmationComponent()
    }

    open fun initializeComponent(): AppComponent {
        return DaggerAppComponent.factory().create(applicationContext)
    }

    open fun initializeConfirmationComponent(): ConfirmationComponent {
        return DaggerConfirmationComponent.builder().appComponent(appComponent).build()
    }
}

@ApplicationScope
@Component(modules = [NetworkModule::class])
interface AppComponent {
    @Component.Factory
    interface Factory {
        fun create(@BindsInstance context: Context) : AppComponent
    }
    fun inject(activity: MainActivity)
    fun inject(fragment: ConfirmationFragment)
}

@ConfirmationScope
@Component(dependencies = [AppComponent::class])
interface ConfirmationComponent {
    fun inject(fragment: ConfirmationFragment)
}

@ApplicationScope
class AModel @Inject constructor() {}

@ConfirmationScope
class BModel @Inject constructor() {}

class ConfirmationFragment : Fragment() {
    @Inject
    lateinit var modelA : AModel

    @Inject
    lateinit var modelB : BModel

    override fun onAttach(context: Context) {
        super.onAttach(context)
        (requireActivity().applicationContext as MyApplication).confirmationComponent.inject(this)
    }
    // Rest of the code
}

最佳答案

我认为你应该换一种方式。如果我的理解正确,ModelA 的范围比 ModelB 大,这意味着您可以将 ModelB 作为 ModelA 的子组件,但范围更窄。

所以为此你需要:

  • 确认组件
  • //@YourScopeAnnotation
    @Subcomponent(modules = [...]) // if it is dependent on any modules
    interface ConfirmationComponent {
    
        // needed for dagger to create component
        @Subcomponent.Factory
        interface Factory {
            fun create(): ConfirmationComponent
        }
    
    
        fun inject(yourFragment: Fragment) // fun inject your fragment
    }
    
  • 子组件模块
  • @Module(
        subcomponents = [ConfirmationComponent::class]
    )
    class SubcomponentsModule
    
  • 在您的应用程序组件中
  • //@ApplicationScopeAnnotation  I think you can also use @Singleton
    @Component(
        modules = [NetworkModule::class, SubcomponentsModule::class]
    )
    interface ApplicationComponent {
    
        fun inject(activity: MainActivity)
        fun confirmationComponent(): ConfirmationComponent.Factory
    
    }
    
  • 而不是像往常一样在你的 Application 类中初始化 ApplicationComponent
  • 现在在您的主要 Activity 中注入(inject) ModelA ,它应该在全局范围内可用。同时在您的 Activity 中创建 ConfirmationComponent
  • @Inject
    lateinit var modelA : AModel
    
    lateinit var confirmationComponent: ConfirmationComponent
    
    override fun onCreate(savedInstanceState: Bundle?) {
        confirmationComponent = (applicationContext as MyApplication).appComponent
                .confirmationComponent()
                .create()
    
        modelA = (applicationContext as MyApplication).appComponent.inject(this)
    
    }
    
  • 最后一步,在您的 fragment 中注入(inject) modelB 并从 Activity
  • 中获取 modelA
    @Inject
        lateinit var modelB: ModelB // inject modelB
    
        lateinit var modelA: ModelA // get ModelA from activity where it was already injected
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
    
            (activity as MainActivity).confirmationComponent.inject(this)
    
            modelA = (activity as MainActivity).modelA
    
        }
    

    我希望这有帮助 :)

    关于android - 如何解决不同范围的绑定(bind)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61289968/

    相关文章:

    android - Android 中的 InputTextLayout setError() 方法不起作用

    android - 非法状态异常 : Activity has been destroyed (API level <21)

    android - 无法从本地日期转换为伦敦日期对象

    java - 如果没有 @Inject 构造函数,则无法提供 Dagger2

    java - Dagger 无法提供我的依赖项

    安卓错误 "android.app.Application does not implement dagger.android.HasActivityInjector"

    android - 在 Android 中通过 Intent 打开 Google Plus 页面

    android - 获取主 Gmail 帐户状态

    android - notifyDataSetChanged 使应用程序崩溃

    android - 可扩展 kotlin 中的 TextView