创建具有依赖项的 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 | 提供对用于构造 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 Multiplatform 模块中创建的,因此无法访问 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 或 Jetpack Compose 实例化 ViewModel。
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 所需的依赖项,还需要从另一个类扩展:
- AndroidViewModelFactory(如果需要- Application类)。
- AbstractSavedStateViewModelFactory(如果需要将- SavedStateHandle作为依赖项进行传递)。
如果不需要 Application 或 SavedStateHandle,则只需从 ViewModelProvider.Factory 进行扩展。
以下示例对 ViewModel 使用 AbstractSavedStateViewModelFactory,因为该 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 的已保存状态模块
- 保存界面状态
- LiveData 概览
