创建带有依赖项的 ViewModel 属于 Android Jetpack 的一部分。
遵循依赖注入的最佳实践,ViewModel 可以将其依赖项作为参数在其构造函数中接收。这些类型主要来自域或数据层。因为框架提供 ViewModel,所以需要一个特殊的机制来创建它们的实例。这个机制就是ViewModelProvider.Factory
接口。只有**此接口的实现才能在正确的范围内实例化 ViewModel**。
带有 CreationExtras 的 ViewModel
如果ViewModel
类在其构造函数中接收依赖项,请提供一个实现ViewModelProvider.Factory
接口的工厂。重写create(Class<T>, CreationExtras)
函数以提供 ViewModel 的新实例。
CreationExtras
允许您访问有助于实例化 ViewModel 的相关信息。以下是可从 extras 访问的键列表
键 | 功能 |
---|---|
ViewModelProvider.NewInstanceFactory.VIEW_MODEL_KEY |
提供对传递给ViewModelProvider.get() 的自定义键的访问。 |
ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY |
提供对Application 类的实例的访问。 |
SavedStateHandleSupport.DEFAULT_ARGS_KEY |
提供对您应该用于构建SavedStateHandle 的参数 Bundle 的访问。 |
SavedStateHandleSupport.SAVED_STATE_REGISTRY_OWNER_KEY |
提供对用于构建ViewModel 的SavedStateRegistryOwner 的访问。 |
SavedStateHandleSupport.VIEW_MODEL_STORE_OWNER_KEY |
提供对用于构建ViewModel 的ViewModelStoreOwner 的访问。 |
要创建SavedStateHandle
的新实例,请使用CreationExtras.createSavedStateHandle()
函数并将其传递给 ViewModel。
带有 APPLICATION_KEY 的 CreationExtras
以下是提供ViewModel
实例的示例,该实例采用对Application
类和SavedStateHandle
进行范围限定的存储库作为依赖项
Kotlin
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.CreationExtras
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 = object : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(
modelClass: Class<T>,
extras: CreationExtras
): T {
// Get the Application object from extras
val application = checkNotNull(extras[APPLICATION_KEY])
// Create a SavedStateHandle for this ViewModel from extras
val savedStateHandle = extras.createSavedStateHandle()
return MyViewModel(
(application as MyApplication).myRepository,
savedStateHandle
) as T
}
}
}
}
Java
import static androidx.lifecycle.SavedStateHandleSupport.createSavedStateHandle;
import static androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY;
import androidx.lifecycle.SavedStateHandle;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.viewmodel.ViewModelInitializer;
public class MyViewModel extends ViewModel {
public MyViewModel(
MyRepository myRepository,
SavedStateHandle savedStateHandle
) { /* Init ViewModel here */ }
static final ViewModelInitializer<MyViewModel> initializer = new ViewModelInitializer<>(
MyViewModel.class,
creationExtras -> {
MyApplication app = (MyApplication) creationExtras.get(APPLICATION_KEY);
assert app != null;
SavedStateHandle savedStateHandle = createSavedStateHandle(creationExtras);
return new MyViewModel(app.getMyRepository(), savedStateHandle);
}
);
}
然后,您可以在检索 ViewModel 实例时使用此工厂
Kotlin
import androidx.activity.viewModels
class MyActivity : AppCompatActivity() {
private val viewModel: MyViewModel by viewModels { MyViewModel.Factory }
// Rest of Activity code
}
Java
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.ViewModelProvider;
public class MyActivity extends AppCompatActivity {
MyViewModel myViewModel = new ViewModelProvider(
this,
ViewModelProvider.Factory.from(MyViewModel.initializer)
).get(MyViewModel.class);
// Rest of Activity code
}
Jetpack Compose
import androidx.lifecycle.viewmodel.compose.viewModel
@Composable
fun MyScreen(
modifier: Modifier = Modifier,
viewModel: MyViewModel = viewModel(factory = MyViewModel.Factory)
) {
// ...
}
或者,使用ViewModel
工厂 DSL 使用更惯用的 Kotlin API 创建工厂
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
)
}
}
}
}
将自定义参数作为 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 for your dependency
val MY_REPOSITORY_KEY = object : 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,
)
}
}
}
}
您可以使用来自 ViewModelStoreOwner
(例如 ComponentActivity
、Fragment
或 NavBackStackEntry
)的 CreationExtras.Key
实例化一个 ViewModel
,也可以使用 Jetpack Compose。
Kotlin
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelStoreOwner
import androidx.lifecycle.viewmodel.CreationExtras
import androidx.lifecycle.viewmodel.MutableCreationExtras
// ...
// Use from ComponentActivity, Fragment, NavBackStackEntry,
// or another ViewModelStoreOwner.
val viewModelStoreOwner: ViewModelStoreOwner = this
val myViewModel: MyViewModel = ViewModelProvider.create(
viewModelStoreOwner,
factory = MyViewModel.Factory,
extras = MutableCreationExtras().apply {
set(MyViewModel.MY_REPOSITORY_KEY, myRepository)
},
)[MyViewModel::class]
Jetpack Compose
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,
)
}
2.5.0 之前的 ViewModel 版本的工厂
如果您使用的是低于 2.5.0 版本的 ViewModel
,则需要从扩展 ViewModelProvider.Factory
并实现 create(Class<T>)
函数的子集类中提供工厂。根据 ViewModel
需要哪些依赖项,需要从不同的类扩展:
- 如果需要
Application
类,则使用AndroidViewModelFactory
。 - 如果需要将
SavedStateHandle
作为依赖项传递,则使用AbstractSavedStateViewModelFactory
。
如果不需要 Application
或 SavedStateHandle
,只需从 ViewModelProvider.Factory
扩展即可。
以下示例使用 AbstractSavedStateViewModelFactory
为一个 ViewModel 创建工厂,该 ViewModel 将仓库和 SavedStateHandle
类型作为依赖项。
Kotlin
class MyViewModel(
private val myRepository: MyRepository,
private val savedStateHandle: SavedStateHandle
) : ViewModel() {
// ViewModel logic ...
// Define ViewModel factory in a companion object
companion object {
fun provideFactory(
myRepository: MyRepository,
owner: SavedStateRegistryOwner,
defaultArgs: Bundle? = null,
): AbstractSavedStateViewModelFactory =
object : AbstractSavedStateViewModelFactory(owner, defaultArgs) {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(
key: String,
modelClass: Class<T>,
handle: SavedStateHandle
): T {
return MyViewModel(myRepository, handle) as T
}
}
}
}
Java
import androidx.annotation.NonNull;
import androidx.lifecycle.AbstractSavedStateViewModelFactory;
import androidx.lifecycle.SavedStateHandle;
import androidx.lifecycle.ViewModel;
public class MyViewModel extends ViewModel {
public MyViewModel(
MyRepository myRepository,
SavedStateHandle savedStateHandle
) { /* Init ViewModel here */ }
}
public class MyViewModelFactory extends AbstractSavedStateViewModelFactory {
private final MyRepository myRepository;
public MyViewModelFactory(
MyRepository myRepository
) {
this.myRepository = myRepository;
}
@SuppressWarnings("unchecked")
@NonNull
@Override
protected <T extends ViewModel> T create(
@NonNull String key, @NonNull Class<T> modelClass, @NonNull SavedStateHandle handle
) {
return (T) new MyViewModel(myRepository, handle);
}
}
然后,您可以使用工厂来检索您的 ViewModel。
Kotlin
import androidx.activity.viewModels
class MyActivity : AppCompatActivity() {
private val viewModel: MyViewModel by viewModels {
MyViewModel.provideFactory((application as MyApplication).myRepository, this)
}
// Rest of Activity code
}
Java
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.ViewModelProvider;
public class MyActivity extends AppCompatActivity {
MyViewModel myViewModel = new ViewModelProvider(
this,
ViewModelProvider.Factory.from(MyViewModel.initializer)
).get(MyViewModel.class);
// Rest of Activity code
}
Jetpack Compose
import androidx.lifecycle.viewmodel.compose.viewModel
@Composable
fun MyScreen(
modifier: Modifier = Modifier,
viewModel: MyViewModel = viewModel(
factory = MyViewModel.provideFactory(
(LocalContext.current.applicationContext as MyApplication).myRepository,
owner = LocalSavedStateRegistryOwner.current
)
)
) {
// ...
}
推荐内容
- 注意:当 JavaScript 关闭时,将显示链接文本。
- ViewModel 的 Saved State 模块
- 保存 UI 状态
- LiveData 概述