Compose OutlinedTextField输入无响应 requestCursorUpdates错误修复
问题现象
在ViewModel中使用Data Class作为状态持有类时,页面内多个OutlinedTextField输入框输入内容无任何响应。每次通过软键盘输入字符时,Logcat输出如下Debug级警告日志,但不会抛出运行时异常:
W/RecordingIC: requestCursorUpdates is not supported
涉及原有代码如下:
状态数据类定义
data class ShoppingListItemState( val name: String = "", val category: String = "", val quantity: String = "", val unit: String = "", val ppu: String = "", val notes: String = "", val hasImage: Boolean = false, val imageUri: Uri? = null )
原有ViewModel实现
class ShoppingListScreenViewModel(): ViewModel() { val shoppingListItemState = mutableStateOf(ShoppingListItemState()) fun setListItemStateValue(stateToEdit: String, stateValue: String) { val item = shoppingListItemState.value when (stateToEdit) { "Name" -> item.copy(name = stateValue) "Category" -> item.copy(category = stateValue) "Quantity" -> item.copy(quantity = stateValue) "Unit" -> item.copy(unit = stateValue) "PPU" -> item.copy(ppu = stateValue) "Notes" -> item.copy(notes = stateValue) "HasImage" -> item.copy(hasImage =stateValue.toBoolean()) "ImageUri" -> item.copy(imageUri = stateValue.toUri()) } shoppingListItemState.value = item } }
输入框调用代码
val shoppingListScreenViewModel: ShoppingListScreenViewModel = viewModel() CustomOutlinedTextField( modifier = Modifier .fillMaxWidth() .onPreviewKeyEvent { if (it.key == Key.Tab) { focusManager.moveFocus(FocusDirection.Down) true } else { false } }, label = stringResource(id = R.string.item_name), inputVal = shoppingListScreenViewModel.shoppingListItemState.value.name, isSingleLine = true, keyboardOptions = KeyboardOptions.Default.copy( capitalization = KeyboardCapitalization.Sentences, autoCorrect = false, keyboardType = KeyboardType.Text, imeAction = ImeAction.Next ), keyboardActions = KeyboardActions( onNext = { focusManager.moveFocus(FocusDirection.Down) } ) ) { shoppingListScreenViewModel.setListItemStateValue("Name", it) }
自定义输入框实现
@Composable fun CustomOutlinedTextField( modifier: Modifier = Modifier, label: String = "", inputVal: String, isSingleLine: Boolean = false, maxLines: Int = 0, keyboardOptions: KeyboardOptions = KeyboardOptions.Default, keyboardActions: KeyboardActions = KeyboardActions.Default, onValChange: (String) -> Unit ) { OutlinedTextField( value = inputVal, onValueChange = { onValChange(it) }, label = { Text(text = label) }, singleLine = isSingleLine, maxLines = maxLines, keyboardOptions = keyboardOptions, keyboardActions = keyboardActions, modifier = modifier ) }
问题根因
输入无响应和日志中的requestCursorUpdates is not supported警告无关,该警告是部分厂商定制输入法对输入法框架接口的不兼容提示,不影响正常输入逻辑。
核心问题出在状态更新逻辑:Kotlin data class的copy()方法会生成属性更新后的全新对象实例,不会修改原有实例。原ViewModel代码中when分支调用copy()后没有接收返回的新对象,最后将未做任何修改的旧item实例重新赋值给状态,Compose无法检测到状态的实际变化,不会触发重组,输入框始终显示初始空字符串,表现为输入无响应。
修复方案
修改ViewModel中的状态更新逻辑,直接接收copy()返回的新状态实例赋值给状态变量,同时做基础的状态封装优化:
class ShoppingListScreenViewModel: ViewModel() { // 使用by委托简化状态访问,private set禁止外部直接修改状态 var shoppingListItemState by mutableStateOf(ShoppingListItemState()) private set fun setListItemStateValue(stateToEdit: String, stateValue: String) { // 直接将copy生成的新实例赋值给状态,确保状态引用更新触发重组 shoppingListItemState = when (stateToEdit) { "Name" -> shoppingListItemState.copy(name = stateValue) "Category" -> shoppingListItemState.copy(category = stateValue) "Quantity" -> shoppingListItemState.copy(quantity = stateValue) "Unit" -> shoppingListItemState.copy(unit = stateValue) "PPU" -> shoppingListItemState.copy(ppu = stateValue) "Notes" -> shoppingListItemState.copy(notes = stateValue) "HasImage" -> shoppingListItemState.copy(hasImage = stateValue.toBoolean()) "ImageUri" -> shoppingListItemState.copy(imageUri = stateValue.toUri()) // 补充else分支避免分支遗漏导致状态异常 else -> shoppingListItemState } } }
修改完成后状态可正常更新,输入框输入会实时响应。
内容的提问来源于stack exchange,提问作者Raj Narayanan
相关产品推荐
相关产品推荐

