欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 财经 > 创投人物 > Jetpack Compose 与 ViewModel 的完美结合

Jetpack Compose 与 ViewModel 的完美结合

2025/6/14 7:15:02 来源:https://blog.csdn.net/wulong756273/article/details/148531135  浏览:    关键词:Jetpack Compose 与 ViewModel 的完美结合

在 Jetpack Compose 中,ViewModel 是管理 UI 状态和业务逻辑的核心组件。它与 Compose 的响应式编程模型完美契合,下面是详细的整合方法和最佳实践。

基本集成方式

1. 添加必要依赖

dependencies {implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.6.2'implementation 'androidx.compose.runtime:runtime-livedata:1.5.4'
}

2. 创建 ViewModel

class CounterViewModel : ViewModel() {// 使用 StateFlow 管理状态private val _count = MutableStateFlow(0)val count: StateFlow<Int> = _count.asStateFlow()fun increment() {_count.value += 1}fun reset() {_count.value = 0}
}

3. 在 Compose 中使用 ViewModel

@Composable
fun CounterScreen() {// 获取 ViewModel 实例val viewModel: CounterViewModel = viewModel()// 将 StateFlow 转换为 Compose 状态val count by viewModel.count.collectAsState()Column(modifier = Modifier.fillMaxSize(),verticalArrangement = Arrangement.Center,horizontalAlignment = Alignment.CenterHorizontally) {Text(text = "计数: $count", style = MaterialTheme.typography.h4)Spacer(modifier = Modifier.height(16.dp))Button(onClick = { viewModel.increment() }) {Text("增加")}Button(onClick = { viewModel.reset() },modifier = Modifier.padding(top = 8.dp)) {Text("重置")}}
}

进阶用法

1. 处理复杂状态

class UserViewModel : ViewModel() {// 使用密封类管理多种状态private val _userState = MutableStateFlow<UserState>(UserState.Loading)val userState: StateFlow<UserState> = _userState.asStateFlow()init {loadUserData()}private fun loadUserData() {viewModelScope.launch {_userState.value = UserState.Loadingtry {val user = userRepository.getUser()_userState.value = UserState.Success(user)} catch (e: Exception) {_userState.value = UserState.Error(e.message ?: "未知错误")}}}fun retry() {loadUserData()}
}sealed class UserState {object Loading : UserState()data class Success(val user: User) : UserState()data class Error(val message: String) : UserState()
}

2. 在 Compose 中处理复杂状态

@Composable
fun UserProfileScreen() {val viewModel: UserViewModel = viewModel()val userState by viewModel.userState.collectAsState()when (val state = userState) {is UserState.Loading -> {Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {CircularProgressIndicator()}}is UserState.Success -> {UserDetailsView(user = state.user)}is UserState.Error -> {ErrorView(message = state.message,onRetry = { viewModel.retry() })}}
}

3. 使用 Hilt 依赖注入

// 添加 Hilt 依赖
implementation 'com.google.dagger:hilt-android:2.48.1'
kapt 'com.google.dagger:hilt-compiler:2.48.1'
implementation 'androidx.hilt:hilt-navigation-compose:1.1.0'

// 使用 @HiltViewModel 注解
@HiltViewModel
class SettingsViewModel @Inject constructor(private val settingsRepository: SettingsRepository
) : ViewModel() {private val _theme = MutableStateFlow(AppTheme.SYSTEM)val theme: StateFlow<AppTheme> = _theme.asStateFlow()init {loadSettings()}private fun loadSettings() {viewModelScope.launch {_theme.value = settingsRepository.getTheme()}}fun setTheme(theme: AppTheme) {viewModelScope.launch {settingsRepository.saveTheme(theme)_theme.value = theme}}
}// 在 Compose 中使用
@Composable
fun SettingsScreen(viewModel: SettingsViewModel = hiltViewModel()) {val theme by viewModel.theme.collectAsState()// UI 实现...
}

最佳实践

1. 状态管理原则

原则说明
单一数据源ViewModel 应是 UI 状态的唯一真实来源
单向数据流UI 事件 → ViewModel → 更新状态 → UI 刷新
状态最小化只暴露 UI 需要的最小状态
不可变性对外暴露的状态应是不可变的(使用 StateFlow 或 LiveData)

2. 状态提升模式

@Composable
fun UserInputSection(username: String,onUsernameChange: (String) -> Unit,password: String,onPasswordChange: (String) -> Unit,onLogin: () -> Unit
) {Column {OutlinedTextField(value = username,onValueChange = onUsernameChange,label = { Text("用户名") })OutlinedTextField(value = password,onValueChange = onPasswordChange,label = { Text("密码") },visualTransformation = PasswordVisualTransformation())Button(onClick = onLogin) {Text("登录")}}
}@Composable
fun LoginScreen(viewModel: LoginViewModel = viewModel()) {val state by viewModel.uiState.collectAsState()UserInputSection(username = state.username,onUsernameChange = viewModel::updateUsername,password = state.password,onPasswordChange = viewModel::updatePassword,onLogin = viewModel::login)if (state.isLoading) {CircularProgressIndicator()}
}

3. 处理副作用

@Composable
fun LoginScreen(viewModel: LoginViewModel = viewModel()) {val state by viewModel.uiState.collectAsState()// 处理导航副作用val navController = rememberNavController()LaunchedEffect(state.isLoginSuccess) {if (state.isLoginSuccess) {navController.navigate("home")}}// 处理错误提示val context = LocalContext.currentLaunchedEffect(state.errorMessage) {state.errorMessage?.let {Toast.makeText(context, it, Toast.LENGTH_SHORT).show()viewModel.errorShown()}}// UI 实现...
}

4. ViewModel 生命周期管理

@Composable
fun MyApp() {val navController = rememberNavController()val backstackEntry by navController.currentBackStackEntryAsState()// 获取当前路由的 ViewModelval currentRoute = backstackEntry?.destination?.routeval viewModelStoreOwner = backstackEntry ?: LocalViewModelStoreOwner.currentScaffold { innerPadding ->NavHost(navController = navController,startDestination = "home",modifier = Modifier.padding(innerPadding)) {composable("home") {// HomeScreen 使用当前导航条目的 ViewModelval homeViewModel: HomeViewModel = viewModel(viewModelStoreOwner)HomeScreen(viewModel = homeViewModel)}composable("profile") {ProfileScreen()}}}
}

常见问题解决方案

1. 状态持久化

class CounterViewModel(savedStateHandle: SavedStateHandle) : ViewModel() {companion object {private const val COUNT_KEY = "count"}private val _count = MutableStateFlow(savedStateHandle.get<Int>(COUNT_KEY) ?: 0)val count: StateFlow<Int> = _count.asStateFlow()init {// 保存状态到 SavedStateHandleviewModelScope.launch {_count.collect { count ->savedStateHandle[COUNT_KEY] = count}}}fun increment() {_count.value += 1}
}
 

2. 性能优化

class ProductViewModel : ViewModel() {// 使用 derivedStateOf 优化派生状态private val _products = MutableStateFlow(emptyList<Product>())val products: StateFlow<List<Product>> = _products.asStateFlow()val favoriteProducts: StateFlow<List<Product>> = _products.derivedStateFlow { products.value.filter { it.isFavorite }}// 使用 flatMapLatest 处理异步操作val searchQuery = MutableStateFlow("")val searchResults = searchQuery.debounce(300) // 防抖 300ms.flatMapLatest { query ->if (query.isEmpty()) {flowOf(emptyList())} else {productRepository.searchProducts(query)}}.stateIn(scope = viewModelScope,started = SharingStarted.WhileSubscribed(5000),initialValue = emptyList())
}
 

3. 测试策略

class CounterViewModelTest {@Testfun `increment should increase count by 1`() = runTest {// 创建 ViewModelval viewModel = CounterViewModel()// 初始状态验证assertEquals(0, viewModel.count.value)// 执行操作viewModel.increment()// 验证结果assertEquals(1, viewModel.count.value)}
}@Composable
fun CounterPreview() {// 预览模式使用假数据val fakeViewModel = CounterViewModel().apply {_count.value = 5}CounterScreen(viewModel = fakeViewModel)
}
 

总结

Jetpack Compose 与 ViewModel 的结合提供了强大的状态管理能力:

  1. ViewModel 作为状态容器:管理 UI 状态和业务逻辑

  2. 响应式状态更新:使用 StateFlow/LiveData + collectAsState 实现自动刷新

  3. 单向数据流:确保状态变化的可预测性和可维护性

  4. 生命周期感知:自动处理配置更改和资源清理

  5. 依赖注入支持:通过 Hilt 简化依赖管理

遵循这些模式和实践,你可以构建出结构清晰、可维护且高效响应的 Compose 应用。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词