Как разрешить привязки с разными областями? - PullRequest
4 голосов
/ 18 апреля 2020

У меня есть модель (AModel), которую я хотел использовать как синглтон. Я создал пользовательскую область с именем @ApplicationScope, чтобы использовать ее для каждого класса, который мне нужен, только один раз. Поэтому AppComponent и AModel делятся этим @ApplicationScope. У меня есть некоторый фрагмент (ConfirmationFragment), где я хотел бы использовать как AModel, так и BModel. BModel имеет другую область видимости, потому что я хотел бы использовать его в 3 фрагментах, но Amodel нужен везде.

Идея доступа к AModel и BModel состояла в том, чтобы позволить ConfirmationComponent зависеть от AppComponent, где AModel уже доступен. Таким образом, если я добавлю ConfirmationComponent в ConfirmationFragment, я тоже смогу использовать AModel.
Но я получил следующую ошибку: [Dagger/IncompatiblyScopedBindings] ConfirmationComponent scoped with @ConfirmationScope may not reference bindings with different scopes:

Сборка завершается успешно, когда инъекция AModel закомментирована из ConfirmationFragment, но завершается неудачей, когда это не так. «т. Мне также нужен 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
}

1 Ответ

1 голос
/ 20 апреля 2020

Я думаю, вы должны сказать это иначе. Если я правильно понял, у вас ModelA имеет большую область действия, чем ModelB, это означает, что вы можете иметь ModelB в качестве подкомпонента ModelA с более узкой областью действия.

Так что для этого вам потребуется:

  1. 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
}
ПодкомпонентыМодуль
@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

}

Затем просто инициализируйте ApplicationComponent в своем классе Application как обычно

Теперь в вашей основной деятельности введите ModelA, которая должна быть доступна глобально. Также создайте 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)

}
Последний шаг, в свой фрагмент вставьте модель B и получите модель A из действия
@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

    }

Надеюсь, это поможет:)

...