Dagger 2:如何从FragmentFactory的子组件绑定父组件中的Fragment Map

时间:2019-03-07 12:32:17

标签: android android-fragments dagger-2 dagger

我有Dagger 2配置:

AppComponent.kt

static IntPtr pointer;

public void UnmanagedAllocation()
{
    pointer = Marshal.AllocHGlobal(1024 * 1024 * 1024 );
}

ActivityBindingModule.kt

-- Usage Summary RgnCount ----------- Total Size -------- %ofBusy %ofTotal
Free             59          762f7000 (   1.847 GB)           46.17%
<unknown>        98          4493e000 (   1.072 GB)  49.76%   26.79%
Heap             15          40158000 (   1.001 GB)  46.50%   25.03%
Image            174           2db2000 (  45.695 MB)   2.07%    1.12%
MappedFile       15           1c51000 (  28.316 MB)   1.28%    0.69%
Stack            24            800000 (   8.000 MB)   0.36%    0.20%

MainActivityModule.kt

@Singleton
@Component(
    modules = [
        AndroidSupportInjectionModule::class,
        AppModule::class,
        ActivityBindingModule::class,
    ]
)
interface AppComponent : AndroidInjector<AppApplication> {
    @Component.Builder
    abstract class Builder : AndroidInjector.Builder<AppApplication>()
}

FragmentModule.kt

@Module
abstract class ActivityBindingModule {
    @ActivityScoped
    @ContributesAndroidInjector(
        modules = [
            MainActivityModule::class,
            FragmentModule::class //a fragment factory for each activity
        ]
    )
    internal abstract fun mainActivity(): MainActivity
}

DefaultFragmentFactory.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
}

我在这里想要做的是使用@Module abstract class FragmentModule { @Binds internal abstract fun bindFragmentFactory(factory: DefaultFragmentFactory): FragmentFactory } 创建@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连接的所有内容,注入工作正常。

此方法的问题在于,无法正确划分Fragment的范围,如果Fragment被销毁,则以下所有子Fragment都将销毁,这将迫使Factory在下一次调用时创建新实例。

因此,我决定添加一个名为LoginFragmentSubcomponent的@Binds @IntoMap @FragmentKey(LoginFragment::class) abstract fun bindLoginFragment(loginFragment: LoginFragment): Fragment 以便能够在其上定义LoginFragmentSubcomponent。 现在的问题是,在Subcomponent中,我无法从模块@FragmentScoped中为我需要的父LoginFragmentModule做出贡献,

Map

事实上,我在编译时收到的错误是:

DefaultFragmentFactory

此处有一个带有可重现问题的示例存储库shx

我该如何解决? 我确定我做错了什么,因为我仍在学习Dagger 2和/或我不了解问题的某些部分以及它应该如何工作。

使用匕首2.21

预先感谢

  

PS:Map<Class<out Fragment>, @JvmSuppressWildcards Provider<Fragment>> 注入背后的想法来自于   很棒的帖子:   https://github.com/matpag/dagger-test-fragmentfactory我只是稍作调整。

0 个答案:

没有答案