Open Berki2021 opened 3 years ago
Okay, I found the actual problem. It has nothing to do with constructor injecting my fragments, but with my base class BusEventFragment
. Because loadFragmentClass
tries to load a fragment of type androidx.fragment.Fragment
and not my special desired BusEventFragment
, this does not work. I will try to work around and do this with my custom class
Your FragmentFactory has one big flaw: If one wants to inject dependencies that need a fragment instance, it is not possible, because you are installing your FragmentFactoryModule
inside SingletonComponent::class
and therefore you can't get lifecycleaware dependencies into your fragments, because they have to be injected inside FragmentComponent::class
Okay, here is the final fix for the problem and the correct way to instantiate all objects:
@Module
@InstallIn(FragmentComponent::class) // NOT SINGLETONCOMPONENT::CLASS
abstract class FragmentFactoryModule {
@Binds
@IntoMap
@FragmentKey(FirstFragment::class)
abstract fun bindFirstFragment(fragment: FirstFragment): Fragment
@Binds
@IntoMap
@FragmentKey(SecondFragment::class)
abstract fun bindSecondFragment(fragment: SecondFragment): Fragment
@Binds
@IntoMap
@FragmentKey(ThirdFragment::class)
abstract fun bindThirdFragmentt(fragment: ThirdFragment): Fragment
}
@MapKey
@Retention(AnnotationRetention.RUNTIME)
annotation class FragmentKey(val value: KClass<out Fragment>)
@Module
@InstallIn(FragmentComponent::class) // Since fragments are only available in FragmentComponent::class
abstract class NavHostModule {
@Binds
abstract fun provideNavHostFragment(fragment: MainFragmentFactory): FragmentFactory
}
@Module
@InstallIn(FragmentComponent::class)
object FragmentModule {
@Provides
fun provideMainFragmentFactory(providerMap: Map<Class<out Fragment>, @JvmSuppressWildcards Provider<Fragment>>)
= MainFragmentFactory(providerMap)
}
@Singleton
class MainFragmentFactory (
private val providerMap: Map<Class<out Fragment>, @JvmSuppressWildcards Provider<Fragment>>
) : FragmentFactory() {
override fun instantiate(classLoader: ClassLoader, className: String): Fragment {
val fragmentClass = loadFragmentClass(classLoader, className)
val creator = providerMap[fragmentClass] ?: providerMap.entries.firstOrNull {
fragmentClass.isAssignableFrom(it.key)
}?.value
return creator?.get() ?: super.instantiate(classLoader, className)
}
}
@AndroidEntryPoint
class MainNavHostFragment : NavHostFragment() {
@Inject lateinit var mainFragmentFactory: FragmentFactory
override fun onAttach(context: Context) {
super.onAttach(context)
childFragmentManager.fragmentFactory = mainFragmentFactory
}
}
Hello sir, I tried to implement your "improved fragmentfactory" as you had shown here.
The problem I have is, that I get the following error:
Here are my fragments:
DocumentFragment
When I delete my dependencies from my fragment-constructor, everything works fine. Does that mean, that we are not able to constructor inject with your "improved" method??