如何解析具有不同作用域的绑定?
bounty到期在7天内。该问题的答案有资格获得 + 50声望赏金。 roncsak想要 引起更多关注对此问题。

我有一个要用作单例的模型(AModel)。我创建了一个名为@ApplicationScope的自定义范围,以将其用于只需要使用一次的每个类。因此,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:

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

我该如何解决此问题?(以防万一,这很重要:我只使用一个活动,而让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
}
0
投票

我想您应该反过来说。如果我正确地理解了您,ModelA的范围比ModelB大,则意味着您可以将ModelB作为ModelA的子组件,范围更窄。

因此,您需要:

ConfirmationComponent
//@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
}
SubcomponentsModule
@Module(
    subcomponents = [ConfirmationComponent::class]
)
class SubcomponentsModule
在您的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

}

比往常一样,只需在Application类中初始化ApplicationComponent

现在在您的主要活动中注入应该在全球范围内可用的ModelA

@Inject
lateinit var modelA : AModel

override fun onCreate(savedInstanceState: Bundle?) {

    modelA = (applicationContext as MyApplication).appComponent.inject(this)

}
最后一步,在片段中注入modelB并从活动中获取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?.applicationContext as MyApplication).appComponent.confirmationComponent().create()
            .inject(this)
        modelA = (activity as MainActivity).modelA

    }

我希望这会有所帮助:)