У меня есть эта конфигурация Dagger 2:
AppComponent.kt
@Singleton
@Component(
modules = [
AndroidSupportInjectionModule::class,
AppModule::class,
ActivityBindingModule::class,
]
)
interface AppComponent : AndroidInjector<AppApplication> {
@Component.Builder
abstract class Builder : AndroidInjector.Builder<AppApplication>()
}
ActivityBindingModule.kt
@Module
abstract class ActivityBindingModule {
@ActivityScoped
@ContributesAndroidInjector(
modules = [
MainActivityModule::class,
FragmentModule::class //a fragment factory for each activity
]
)
internal abstract fun mainActivity(): MainActivity
}
MainActivityModule.kt
@Module(subcomponents = [LoginFragmentSubcomponent::class])
abstract class MainActivityModule {
//uncommenting this works fine but Fragment can't be scoped
//@Binds
//@IntoMap
//@FragmentKey(LoginFragment::class)
//abstract fun bindLoginFragment(loginFragment: LoginFragment): Fragment
//...other things which work fine
}
@Subcomponent(modules = [LoginFragmentModule::class])
@FragmentScoped
interface LoginFragmentSubcomponent : AndroidInjector<LoginFragment> {
@Subcomponent.Builder
abstract class Builder : AndroidInjector.Builder<LoginFragment>()
}
@Module
abstract class LoginFragmentModule {
//this can't be seen from Map used in DefaultFragmentFactory
@Binds
@IntoMap
@FragmentKey(LoginFragment::class)
abstract fun bindLoginFragment(loginFragment: LoginFragment): Fragment
}
FragmentModule.kt
@Module
abstract class FragmentModule {
@Binds
internal abstract fun bindFragmentFactory(factory: DefaultFragmentFactory): FragmentFactory
}
DefaultFragmentFactory.kt
@ActivityScoped
class DefaultFragmentFactory @Inject constructor(
private val creators: Map<Class<out Fragment>, @JvmSuppressWildcards Provider<Fragment>>
) : FragmentFactory() {
//this is deprecated in fragment-ktx 1.1.0-alpha06
//but you need to override this if you were using the bundle
override fun instantiate(classLoader: ClassLoader, className: String, args: Bundle?): Fragment {
return instantiate(classLoader, className).apply { arguments = args }
}
override fun instantiate(classLoader: ClassLoader, className: String): Fragment {
val fragmentClass = loadFragmentClass(classLoader, className)
val found = creators.entries.find { fragmentClass.isAssignableFrom(it.key) }
val provider = found?.value
//if we don't find a match in the map, proceed with the default empty constructor
return if (provider != null) {
provider.get()
} else {
fragmentClass.newInstance()
}
}
}
Я пытаюсь использовать FragmentFactory
для создания Fragments
.
Как описано в коде, я могу раскомментировать следующие строки:
@Binds
@IntoMap
@FragmentKey(LoginFragment::class)
abstract fun bindLoginFragment(loginFragment: LoginFragment): Fragment
и удаление всего, что связано с LoginFragmentSubcomponent
и впрыск работает нормально.
Проблема с этим подходом заключается в том, что фрагмент не может быть должным образом ограничен, таким образом, что, если фрагмент уничтожен, все дочерние фрагменты ниже уничтожаются, что заставит Фабрику создать новый экземпляр при следующем вызове.
Поэтому я решил добавить Subcomponent
с именем LoginFragmentSubcomponent, чтобы иметь возможность определять @FragmentScoped
на нем.
Теперь проблема в том, что из модуля LoginFragmentModule
я не могу внести свой вклад в родительский Map
мне нужно в DefaultFragmentFactory
, который имеет тип:
Map<Class<out Fragment>, @JvmSuppressWildcards Provider<Fragment>>
На самом деле ошибка, которую я получаю во время компиляции:
[Dagger/MissingBinding]
java.util.Map<java.lang.Class<? extends androidx.fragment.app.Fragment>,
javax.inject.Provider<androidx.fragment.app.Fragment>> cannot be provided
without an @Provides-annotated method.
Здесь приведен пример репо с воспроизводимой проблемой : https://github.com/matpag/dagger-test-fragmentfactory
Как я могу решить эту проблему?
Я уверен, что делаю что-то не так, потому что я все еще изучаю Dagger 2 и / или я не понял какую-то часть проблемы и как это должно работать.
Использование Dagger 2.21
Заранее спасибо
PS: Идея этой FragmentFactory
инъекции возникла из этого
потрясающий пост:
https://www.captechconsulting.com/blogs/using-androidxs-fragmentfactory-with-dagger-for-fragment-dependency-injection Я просто немного подправил.