如何消除Kotlin ViewModel中属性变更处理函数的代码重复问题
解决方案
以下两种常用实现方式可消除重复代码:
方案1:通用高阶更新方法(推荐)
直接在ViewModel中暴露接收转换函数的通用更新方法,无需为每个属性单独编写逻辑,新增Input属性时不需要修改ViewModel代码。
修改后的ViewModel代码
data class Input( val email: String = "", val password: String = "" ) class LoginViewModel : ViewModel() { private val _input = MutableStateFlow(Input()) val input = _input.asStateFlow() // 通用更新方法,接收Input的变换逻辑完成状态更新 fun updateInput(transform: (current: Input) -> Input) { _input.value = transform(_input.value) } }
对应界面层代码调整
@Composable fun LoginScreen(loginViewModel: LoginViewModel = viewModel()) { val input by loginViewModel.input.collectAsState() Column { TextField( label = { Text("邮箱") }, value = input.email, onValueChange = { newValue -> loginViewModel.updateInput { current -> current.copy(email = newValue) } }, singleLine = true ) TextField( label = { Text("密码") }, value = input.password, onValueChange = { newValue -> loginViewModel.updateInput { current -> current.copy(password = newValue) } }, singleLine = true ) } }
方案2:基于属性引用的更新方法
适合Input属性数量多、需要集中管控所有属性修改逻辑的场景。
修改后的ViewModel代码
import kotlin.reflect.KProperty1 data class Input( val email: String = "", val password: String = "" ) class LoginViewModel : ViewModel() { private val _input = MutableStateFlow(Input()) val input = _input.asStateFlow() fun <T> updateProperty(property: KProperty1<Input, T>, value: T) { _input.update { current -> @Suppress("UNCHECKED_CAST") when(property) { Input::email -> current.copy(email = value as String) Input::password -> current.copy(password = value as String) else -> current } } } }
对应界面层代码调整
@Composable fun LoginScreen(loginViewModel: LoginViewModel = viewModel()) { val input by loginViewModel.input.collectAsState() Column { TextField( label = { Text("邮箱") }, value = input.email, onValueChange = { loginViewModel.updateProperty(Input::email, it) }, singleLine = true ) TextField( label = { Text("密码") }, value = input.password, onValueChange = { loginViewModel.updateProperty(Input::password, it) }, singleLine = true ) } }
方案对比
- 高阶函数方案:无额外维护成本,灵活性高,适配所有修改场景(包括同时修改多个属性),是绝大多数场景下的首选。
- 属性引用方案:调用逻辑更统一,可在ViewModel层集中校验所有属性修改操作,缺点是新增Input属性时需要同步更新ViewModel中的when分支。
内容的提问来源于stack exchange,提问作者Boaris
相关产品推荐
相关产品推荐

