Android Jetpack Compose MVVM模式下TextField无法触发重组问题求助
问题原因
- Jetpack Compose的
mutableStateOf默认通过引用相等性判断是否需要触发重组,你当前只修改了Client实例内部的firstName属性,updatedClientData持有的对象引用没有发生变化,所以State无法感知到数据变更,不会触发重组。 - 另外你在Composable中直接
MyViewModel()创建实例是错误写法,每次页面重组都会生成新的ViewModel实例,无法保留状态,应该用官方提供的扩展方法获取生命周期感知的ViewModel实例。
修复方案
1. 调整数据类和ViewModel实现
优先使用不可变数据类设计,修改属性时通过copy生成新的实例,触发State的变更感知:
// 修改Client的firstName为val,符合不可变设计规范 data class Client( @SerializedName("Id") val id: Int = 0, @SerializedName("FirstName") val firstName: String = "", @SerializedName("LastName") val lastName: String = "", @SerializedName("Email") val email: String = "", @SerializedName("MobilePhone") val mobilePhone: String = "", ) class MyViewModel() : ViewModel() { var updatedClientData by mutableStateOf<Client>(Client()) init { updatedClientData = Client( id = 1, firstName = "Test", lastName = "User", email = "test.user@domain.com", mobilePhone = "777666555" ) } // 新增属性更新方法,通过copy生成新的Client实例 fun updateFirstName(newName: String) { updatedClientData = updatedClientData.copy(firstName = newName) } }
2. 修正TextField的回调逻辑
@Composable fun GetInput(myVM: MyViewModel) { Column( modifier = Modifier.fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center ) { OutlinedTextField( value = myVM.updatedClientData.firstName, // 调用ViewModel的更新方法,不要直接修改实例内部属性 onValueChange = { myVM.updateFirstName(it) }, label = { Text(text = "Firstname")} ) } }
3. 修正ViewModel的获取方式
不要直接构造ViewModel实例,使用官方扩展方法获取:
// 需引入activity-ktx依赖才可使用by viewModels扩展 class MainActivity : ComponentActivity() { private val myVM by viewModels<MyViewModel>() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { TextFieldRecomposeTheme { Surface(color = MaterialTheme.colors.background) { GetInput(myVM = myVM) } } } } }
内容的提问来源于stack exchange,提问作者Johann Muller
相关产品推荐
相关产品推荐

