匕首2将活动视图模型注入片段

(使用kotlin)我有一个应用程序使用2个片段的设置活动。 我希望两者都能像Activity一样获得SettingsViewModel的同一个实例。 我认为有一个范围问题,我错过了。

首先,我有标准的ViewModelModule

 @Module abstract class ViewModelModule { @Binds @IntoMap @ViewModelKey(SettingsViewModel::class) abstract fun bindSettingsViewModel(viewModel: SettingsViewModel): ViewModel @Binds abstract fun bindViewModelFactory(factory: MyViewModelFactory): ViewModelProvider.Factory } 

我把我的活动绑定在:

 @Module abstract class AndroidBindingModule { @PerActivity @ContributesAndroidInjector(modules = [SettingsActivityModule::class]) abstract fun contributeSettingsActivity(): SettingsActivity } 

随着所有其他的东西,这工作得很好, SettingsActivity也得到了一个SettingsActivity的实例。 SettingsActivityModule添加以下内容:

 @PerFragment @ContributesAndroidInjector abstract fun contributeMainSettingsFragment(): MainSettingsFragment @PerFragment @ContributesAndroidInjector abstract fun contributeDebugSettingsFragment(): DebugSettingsFragment 

这两个片段似乎有调用注入器(我通过调试器检查和AndroidSupportInjection.inject(fragment)被调用)。 这些片段包括:

 @Inject lateinit var mainViewModel: SettingsViewModel 

但在我的片段的onCreate()我看到mainViewModel仍然是空的。 有什么特别的我需要在这里做,以避免调用ViewModelProviders.of(activity)[SettingsViewModel::class.java] ,而不是注入视图模型?

更新:

经过多次阅读后,我发现使用视图模型注入片段的正确方法是注入工厂,并在onActivityCreated获取视图模型:

 @Inject lateinit var viewModelFactory: ViewModelProvider.Factory lateinit var mainViewModel: SettingsViewModel override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) mainViewModel = ViewModelProviders.of(activity, viewModelFactory)[SettingsViewModel::class.java] } 

这是有道理的,因为我有MyViewModelFactory作为ViewModelProvider.Factory绑定和它用MyViewModelFactory注释。 当我尝试编译上述我得到以下错误:

 Error:(6, 1) error: [dagger.android.AndroidInjector.inject(T)] java.util.Map<kotlin.reflect.KClass,? extends javax.inject.Provider> cannot be provided without an @Provides-annotated method. 

看来Dagger找不到ViewModelModule创建的映射。 在这方面,我仍然感到不知所措。 也许我的树不正确? 为什么AndroidBindingModule活动能够获取ViewModel而不是分片?

 AppComponent - AndroidInjectionModule - AndroidBindingModule - AppModule - SdkModule - ViewModelModule - GotItCardModule - ViewHolderSubcomponent (provides a mapping of layout ID -> ViewHolder for a factory) 

UPDATE

我已经做了一些更深入的挖掘…从完整的错误:

 e: /home/user/workspace/Example/sdktest/build/tmp/kapt3/stubs/debug/com/example/sdktest/di/AppComponent.java:6: error: [dagger.android.AndroidInjector.inject(T)] java.util.Map<kotlin.reflect.KClass,? extends javax.inject.Provider> cannot be provided without an @Provides-annotated method. e: e: public abstract interface AppComponent { e: ^ e: java.util.Map<kotlin.reflect.KClass,? extends javax.inject.Provider> is injected at e: com.example.sdktest.di.viewmodel.ExampleViewModelFactory.(creators) e: com.example.sdktest.di.viewmodel.ExampleViewModelFactory is injected at e: com.example.sdktest.di.viewmodel.ViewModelModule.bindViewModelFactory(factory) e: android.arch.lifecycle.ViewModelProvider.Factory is injected at e: com.example.sdktest.ui.settings.fragment.MainSettingsFragment.viewModelFactory e: com.example.sdktest.ui.settings.fragment.MainSettingsFragment is injected at e: dagger.android.AndroidInjector.inject(arg0) 

我认为问题是,不知何故Dagger试图注入我的片段与dagger.android.AndroidInjecton而不是dagger.android.AndroidSupportInjection 。 仍然不知道如何解决。

好的,所以我find了答案,并没有接近我的想法。 我把GithubViewModelFactory翻译成Kotlin包含下面的构造函数:

 @Singleton class MetaverseViewModelFactory @Inject constructor( creators: Map, Provider> ): ViewModelProvider.Factory { private val creators: Map, Provider> = creators.mapKeys { it.key.java } //... } 

这是由于Kotlin中的ViewModelKey只能使用KClass而不是Class 。 事实certificate,kapt照顾这一点,正确的工厂应该是这样的:

 @Singleton class MetaverseViewModelFactory @Inject constructor( private val creators: Map, @JvmSuppressWildcards Provider> ): ViewModelProvider.Factory { //... } 

请注意额外的@JvmSupressWildcards以避免将Provider变成Provider Provider