You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 03:31:03