Jetpack Compose Wear OS物理设备键盘输入崩溃:类型转换异常
解决Wear OS中RemoteInput返回SpannableString导致的ClassCastException崩溃
问题重现
使用Jetpack Compose为Wear OS开发Baybayin(菲律宾古老文字)键盘时,虚拟设备运行正常,但在三星Galaxy Watch 4物理设备上输入文本后应用崩溃,报错:
java.lang.ClassCastException: android.text.SpannableString cannot be cast to java.lang.String
崩溃触发点在以下代码段的强制类型转换:
rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { it.data?.let { data -> val results: Bundle = RemoteInput.getResultsFromIntent(data) val ipAddress: CharSequence? = results.getCharSequence("ip_address") label.value = ipAddress as String // 此处崩溃 }
原因分析
RemoteInput.getCharSequence()返回的CharSequence实例在不同环境下实现类不同:
- 虚拟设备上,输入法可能返回纯
String对象,强制转换as String可以正常执行 - 物理设备(如三星Galaxy Watch4)上,由于Baybayin字体带特殊样式,输入法返回的是带格式的SpannableString,它是
CharSequence的子类但不是String的子类,直接强制类型转换会抛出ClassCastException
解决方案
不要使用强制类型转换,改用CharSequence.toString()方法提取纯文本内容,同时增加空值安全处理,避免空指针异常:
修正后的关键代码
val launcher = rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { it.data?.let { data -> val results: Bundle = RemoteInput.getResultsFromIntent(data) val ipAddress: CharSequence? = results.getCharSequence("ip_address") // 安全转换:提取纯文本,空值时保留原有内容 label.value = ipAddress?.toString() ?: label.value } }
完整修正代码
@Composable fun Keyboard(){ val contentModifier = Modifier .padding(top = 17.dp) .fillMaxWidth() .wrapContentSize(align = Alignment.Center) val label = remember { mutableStateOf("Start")} val launcher = rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { it.data?.let { data -> val results: Bundle = RemoteInput.getResultsFromIntent(data) val ipAddress: CharSequence? = results.getCharSequence("ip_address") // 替换原强制转换为安全的toString()处理 label.value = ipAddress?.toString() ?: label.value } } Column() { Spacer(modifier = Modifier.height(20.dp)) Chip( label = { Text(label.value, style = MaterialTheme.typography.body2)}, //baybayin font style onClick = {} ) Chip( label = { Text("Search with specific IP") }, onClick = { val intent: Intent = RemoteInputIntentHelper.createActionRemoteInputIntent(); val remoteInputs: List<RemoteInput> = listOf( RemoteInput.Builder("ip_address") .setLabel("Manual IP Entry") .wearableExtender { setEmojisAllowed(false) setInputActionType(EditorInfo.IME_ACTION_DONE) }.build() ) RemoteInputIntentHelper.putRemoteInputsExtra(intent, remoteInputs) launcher.launch(intent) } ) } }
说明
toString()方法会自动处理CharSequence的各种实现类(包括SpannableString),提取其中的纯文本内容?: label.value是为空值情况设置默认值,避免label.value被设置为null导致后续UI异常
内容的提问来源于stack exchange,提问作者moemoekyuun
相关产品推荐
相关产品推荐

