创建具有依赖项的 ViewModel   Android Jetpack 的一部分。

按照依赖项注入的最佳实践,ViewModel 可以在其构造函数中将依赖项作为参数。这大多是网域层或数据层中的类型。由于框架提供 ViewModel,因此需要一种特殊机制来创建 ViewModel 的实例。该机制是 ViewModelProvider.Factory 接口。只有此接口的实现才能在适当的作用域内实例化 ViewModel

包含 CreationExtras 的 ViewModel

如果 ViewModel 类在其构造函数中接收依赖项,请提供用于实现 ViewModelProvider.Factory 接口的工厂。替换 create(Class<T>, CreationExtras) 函数以提供 ViewModel 的新实例。

借助 CreationExtras,您可以访问有助于实例化 ViewModel 的相关信息。下面列出了可以通过 extra 访问的键:

功能
ViewModelProvider.NewInstanceFactory.VIEW_MODEL_KEY 提供对您传递给 ViewModelProvider.get() 的自定义键的访问权限。
ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY 提供对 Application 类实例的访问权限。
SavedStateHandleSupport.DEFAULT_ARGS_KEY 提供对您在构造 SavedStateHandle 时应使用的参数 bundle 的访问权限。
SavedStateHandleSupport.SAVED_STATE_REGISTRY_OWNER_KEY 提供对用于构造 ViewModelSavedStateRegistryOwner 的访问权限。
SavedStateHandleSupport.VIEW_MODEL_STORE_OWNER_KEY 提供对用于构造 ViewModelViewModelStoreOwner 的访问权限。

如需创建 SavedStateHandle 的新实例,请使用 CreationExtras.createSavedStateHandle() 函数并将其传递给 ViewModel。

包含 APPLICATION_KEY 的 CreationExtras

以下示例说明了如何提供 ViewModel 的实例,该实例会将作用域限定为 Application 类的存储库SavedStateHandle 作为依赖项:

    import androidx.lifecycle.SavedStateHandle
    import androidx.lifecycle.ViewModel
    import androidx.lifecycle.ViewModelProvider
    import androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory.Companion.APPLICATION_KEY
    import androidx.lifecycle.createSavedStateHandle
    import androidx.lifecycle.viewmodel.initializer
    import androidx.lifecycle.viewmodel.viewModelFactory

    class MyViewModel(
        private val myRepository: MyRepository,
        private val savedStateHandle: SavedStateHandle
    ) : ViewModel() {

        // ViewModel logic
        // ...

        // Define ViewModel factory in a companion object
        companion object {

            val Factory: ViewModelProvider.Factory = viewModelFactory {
                initializer {
                    val savedStateHandle = createSavedStateHandle()
                    val myRepository = (this[APPLICATION_KEY] as MyApplication).myRepository
                    MyViewModel(
                        myRepository = myRepository,
                        savedStateHandle = savedStateHandle
                    )
                }
            }
        }
    }

然后,您可以在检索 ViewModel 的实例时使用此工厂:

import androidx.lifecycle.viewmodel.compose.viewModel

@Composable
fun MyScreen(
    modifier: Modifier = Modifier,
    viewModel: MyViewModel = viewModel(factory = MyViewModel.Factory)
) {
    // ...
}

将自定义参数作为 CreationExtras 传递

您可以通过创建自定义键,通过 CreationExtras 将依赖项传递给 ViewModel。 如果您的 ViewModel 依赖于无法通过 Application 类和 APPLICATION_KEY 访问的对象,这会非常有用。例如,当您的 ViewModel 在 Kotlin 多平台模块内创建时,它无法访问 Android 依赖项。

在此示例中,ViewModel 定义了一个自定义键,并在 ViewModelProvider.Factory 中使用了该键。

import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.CreationExtras
import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory

class MyViewModel(
    private val myRepository: MyRepository,
) : ViewModel() {
    // ViewModel logic

    // Define ViewModel factory in a companion object
    companion object {

        // Define a custom key using the factory function
        val MY_REPOSITORY_KEY = CreationExtras.Key<MyRepository>()

        val Factory: ViewModelProvider.Factory = viewModelFactory {
            initializer {
                // Get the dependency in your factory
                val myRepository = this[MY_REPOSITORY_KEY] as MyRepository
                MyViewModel(
                    myRepository = myRepository,
                )
            }
        }
    }
}

您可以在可组合函数中直接使用 CreationExtras.Key 实例化 ViewModel

import androidx.lifecycle.viewmodel.MutableCreationExtras
import androidx.lifecycle.viewmodel.compose.viewModel
// ...
@Composable
fun MyApp(myRepository: MyRepository) {
    val extras = MutableCreationExtras().apply {
        set(MyViewModel.MY_REPOSITORY_KEY, myRepository)
    }
    val viewModel: MyViewModel = viewModel(
        factory = MyViewModel.Factory,
        extras = extras,
    )
}

其他资源

如需详细了解 ViewModel 和依赖项,请参阅下面列出的其他资源:

文档

查看内容