如何解决不同范围的绑定?

How to resolve bindings with different scopes?

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

同时访问 AModel 和 BModel 的想法是让 ConfirmationComponent 依赖于 AModel 已经可用的 AppComponent。这样,如果我将 ConfirmationComponent 注入 ConfirmationFragment,我也可以使用 AModel。
但我收到以下错误: [Dagger/IncompatiblyScopedBindings] ConfirmationComponent scoped with @ConfirmationScope may not reference bindings with different scopes:

当注入 AModel 被 ConfirmationFragment 注释掉时构建成功,但如果不是,则构建失败。我也需要那个片段中的 AModel。

我该如何解决这个问题?
(以防万一:我只使用一个 activity,让 Android 导航使用片段来完成工作。)

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 的子组件,但范围更窄。

为此你需要:

  1. 确认组件
//@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
}
  1. 子组件模块
@Module(
    subcomponents = [ConfirmationComponent::class]
)
class SubcomponentsModule
  1. 在您的 ApplicationComponent 中
//@ApplicationScopeAnnotation  I think you can also use @Singleton
@Component(
    modules = [NetworkModule::class, SubcomponentsModule::class]
)
interface ApplicationComponent {

    fun inject(activity: MainActivity)
    fun confirmationComponent(): ConfirmationComponent.Factory

}
  1. 不如像往常一样在您的应用程序中初始化 ApplicationComponent class

  2. 现在在您的主程序中 activity 注入应该在全球范围内可用的 ModelA。同时在 activity

  3. 中创建 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)

}
  1. 最后一步,在您的片段中注入 modelB 并从 activity
  2. 获取 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

    }

希望对您有所帮助:)