如何使用 Dagger 2 以最少的样板访问 ViewModel 中的 Arguments/Extras Bundle?

Kir*_*man 10 android dependency-injection kotlin android-architecture-components

我正在将我的应用程序转换为使用ViewModels。为了实例化ViewModels 我使用自定义Factory和 Dagger 2 进行依赖注入。它看起来像这样:

@Singleton
class ViewModelFactory @Inject constructor(
    private val viewModels: Map<Class<out ViewModel>, @JvmSuppressWildcards Provider<ViewModel>>
) : ViewModelProvider.Factory {

    override fun <T : ViewModel> create(modelClass: Class<T>): T 
        = viewModels[modelClass]!!.get() as T
}

@Target(AnnotationTarget.FUNCTION) @Retention(AnnotationRetention.RUNTIME) @MapKey
annotation class ViewModelKey(val value: KClass<out ViewModel>)

@Module
abstract class ViewModelModule {

    @Binds
    abstract fun bindViewModelFactory(factory: ViewModelFactory): ViewModelProvider.Factory

    @Binds @IntoMap @ViewModelKey(FooViewModel::class)
    abstract fun fooViewModel(viewModel: FooViewModel): ViewModel
}
Run Code Online (Sandbox Code Playgroud)

现在我面临的问题,如何访问参数/附加Bundle我的Fragment还是Activity内部的ViewModel。这是必要的,因为视图以及 中的数据ViewModel通常是可参数化的。我将如何使用最少的样板来实现这一点?

Val*_*kov 6

如果您使用Saved State模块,则活动意图附加和片段参数都可以通过SavedStateHandle获得

class SavedStateViewModel(private val state: SavedStateHandle) : ViewModel() {
  init {
    val someArgument = state.get<String>("someArgumentKey")
    ...
  }
}
Run Code Online (Sandbox Code Playgroud)

您还可以使用AssistedInject库将参数从 Activity/Fragment 传递到 ViewModel,但它是一个样板解决方案。这是一个匕首示例另一个使用匕首柄的示例


are*_*res 2

将这些额外的参数/参数注入到你的视图模型中怎么样?您可以通过使用 dagger 访问此类活动/片段来实现此目的。

@Module
class IntentModule {
    @Provides
    fun retriveIntentWithExtraX(activity: DestinationActivity): Long {
        return activity.intent.getSerializableExtra(SOME_EXTRA_DATA) as Long
    }
}
Run Code Online (Sandbox Code Playgroud)

并在模块内部包含您的活动/片段:

@Module
abstract class ActivityModules {

    @ContributesAndroidInjector(modules = [IntentModule::class])
    abstract fun contributeDestinationActivity(): DestinationActivity

}
Run Code Online (Sandbox Code Playgroud)

最后你可以将这样的参数/额外注入到你的 ViewModel 中,如下所示:

class SomeViewModel @Inject constructor(
    private val someExtraData: Long
) : ViewModel() 
Run Code Online (Sandbox Code Playgroud)