如何从 AbstractSavedStateViewModelFactory 动态设置包

Gui*_*lhE 7 android android-lifecycle dagger-2 android-viewmodel viewmodel-savedstate

我的视图模型工厂

class ViewModelFactory @Inject constructor(
    private val viewModelMap: MutableMap<Class<out ViewModel>, ViewModelAssistedFactory<out ViewModel>>,
    owner: SavedStateRegistryOwner,
    defaultArgs: Bundle?
) : AbstractSavedStateViewModelFactory(owner, defaultArgs) {

    @Throws(IllegalStateException::class)
    @Suppress("UNCHECKED_CAST")
    override fun <T : ViewModel?> create(key: String, modelClass: Class<T>, handle: SavedStateHandle): T {
        return viewModelMap[modelClass]?.create(handle) as? T ?: throw IllegalStateException("Unknown ViewModel class")
    }
}
Run Code Online (Sandbox Code Playgroud)

活动

@Inject
lateinit var viewModelFactory: ViewModelFactory
protected val viewModel: ViewModel by lazy { ViewModelProvider(this, viewModelFactory).get(getViewModelClass()) }
Run Code Online (Sandbox Code Playgroud)

视图模型

@AssistedInject.Factory
interface Factory : ViewModelAssistedFactory<SplashViewModel>
Run Code Online (Sandbox Code Playgroud)

我想知道如何动态提供 defaultArgs 而不是:

活动模块

@Module
    companion object {
        @JvmStatic
        @Nullable
        @Provides
        fun provideDefaultArgs(): Bundle? {
            return null
        }
    }
Run Code Online (Sandbox Code Playgroud)

这个想法是能够向 ViewModel 发送一个参数,比如说 DetailActivity 的 ID。通常我使用“init”方法,但如果我可以使用StateHandle map会更好。像这样这样的东西。

说得通?是否可以?

Gui*_*lhE 6

我遇到了两种解决方案:

\n\n

方案一:

\n\n

将我们的 ViewModelFactory 更改为:

\n\n
class ViewModelFactory @Inject constructor(\n    private val viewModelMap: MutableMap<Class<out ViewModel>, ViewModelAssistedFactory<out ViewModel>>\n) {\n    fun create(owner: SavedStateRegistryOwner, defaultArgs: Bundle? = null): AbstractSavedStateViewModelFactory {\n        return object : AbstractSavedStateViewModelFactory(owner, defaultArgs) {\n            @Suppress("UNCHECKED_CAST")\n            override fun <T : ViewModel?> create(key: String, modelClass: Class<T>, handle: SavedStateHandle): T {\n                return viewModelMap[modelClass]?.create(handle) as? T ?: throw IllegalStateException("Unknown ViewModel class")\n            }\n        }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

最后:

\n\n
@Inject\nlateinit var viewModelFactory: ViewModelFactory\nprotected val viewModel: ViewModel by lazy { ViewModelProvider(this, viewModelFactory.create(this, args).get(getViewModelClass()) }\n
Run Code Online (Sandbox Code Playgroud)\n\n

另外,我们可以将 ActivityModule 简化为(示例):

\n\n
@AssistedModule\n@Module(includes = [AssistedInject_SplashActivityModule::class])\nabstract class SplashActivityModule{\n\n    @Binds\n    @IntoMap\n    @ViewModelKey(SplashViewModel::class)\n    abstract fun bindFactory(factory: SplashViewModel.Factory): ViewModelAssistedFactory<out ViewModel>\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

Tom\xc3\xa1\xc5\xa1 Mlynari\xc4\x8d的这篇文章帮助解决了这个问题。

\n\n

方案B:

\n\n

创建一个Factory没有注入依赖项的:

\n\n
class ViewModelFactoryAlt<out V : ViewModel>(\n    private val viewModelFactory: ViewModelAssistedFactory<V>,\n    owner: SavedStateRegistryOwner,\n    defaultArgs: Bundle? = null\n) : AbstractSavedStateViewModelFactory(owner, defaultArgs) {\n\n    @Suppress("UNCHECKED_CAST")\n    override fun <T : ViewModel> create(key: String, modelClass: Class<T>, handle: SavedStateHandle): T {\n        return viewModelFactory.create(handle) as T\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

创建我们的ViewModelAssitedFactory喜欢:

\n\n
class HelloWorldViewModelFactory @Inject constructor(\n    private val dependencyA: DependencyA,\n    ...\n) : ViewModelAssistedFactory<HelloWorldViewModel> {\n    override fun create(stateHandle: SavedStateHandle): HelloWorldViewModel {\n        return HelloWorldViewModel(stateHandle, dependencyA, ...)\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

最后:

\n\n
@Inject\nlateinit var factory: HelloWorldViewModelFactory\nprivate val viewModel: HelloWorldViewModel by viewModels { ViewModelFactoryAlt(factory, this, intent.extras) }\n
Run Code Online (Sandbox Code Playgroud)\n\n

这篇文章埃莱帮助解决了这个问题。

\n