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

为什么修改Compose的remember值后调用JNI会抛出空指针异常

问题根因

  • 第一个核心原因是JNI 调用突破了 Kotlin 空安全约束:你在 Kotlin 层声明的 external fun output(input: String): String 返回值为不可空 String 类型,但 JNI 层返回 NULL 时 Kotlin 不会做非空校验,会直接将 null 赋值给不可空类型的状态 text_output,造成「不可空类型实际持有 null」的隐蔽问题。而 Compose 重组的调用链和普通线性执行逻辑不同,空值引发的崩溃栈会被重组链路掩盖,所以会出现看起来和 JNI 调用无关的 interactionSource 空指针报错。
    初始输入未修改时,固定字符串的 JNI 处理逻辑没有异常,返回值合法所以不会触发问题;修改输入后如果输入内容触发了 C++ 字符串处理的边界问题(比如特殊字符、长度异常)就会导致 JNI 返回 null,进而触发崩溃。
  • 第二个可能的触发原因是Compose 依赖版本未对齐:如果你的项目中 compose-foundation、compose-material 等核心依赖版本不一致,Button 组件的默认参数 interactionSource 会找不到默认实现,修改输入触发全量重组时就会传入 null 触发空指针。

修复方案

1. 修复 JNI 空安全问题

首先修改 Kotlin 层的 external 函数声明,将返回值改为可空类型,调用时增加空校验:

class PseudoStream{
    companion object{
        // 返回值改为可空类型 String?
        external fun output(input: String): String?
    }
}

按钮点击逻辑增加空值处理:

Button(onClick = {
        text_output.value = PseudoStream.output(text_input.value) ?: "处理失败"
    }
){
    Text("Modify")
}

同时检查 C++ 侧逻辑,确保所有执行路径都不会返回 NULL,比如在 Create_Java_String 函数中增加边界判断:

jstring Create_Java_String(JNIEnv *environment, const std::string& mystr){
    if(mystr.empty()){
        return environment->NewStringUTF("");
    }
    return environment->NewStringUTF(mystr.data());
}

2. 对齐 Compose 依赖版本

在项目根目录的 build.gradle 中统一声明 Compose 版本:

buildscript {
    ext {
        compose_version = '1.4.3' // 可替换为任意官方稳定版本
    }
}

所有 Compose 相关依赖都使用统一版本号:

dependencies {
    implementation "androidx.compose.ui:ui:$compose_version"
    implementation "androidx.compose.foundation:foundation:$compose_version"
    implementation "androidx.compose.material:material:$compose_version"
    // 其他compose依赖也统一使用该版本变量
}

可选优化

可以用 Kotlin 属性委托简化 Compose 状态的声明,避免每次调用都写 .value:

import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue

// 状态声明简化
var textInput by remember { mutableStateOf("Initial value ") }
var textOutput by remember { mutableStateOf("") }

// 使用时直接读写变量即可
TextField(
    value = textInput,
    onValueChange = { textInput = it },
)
Button(onClick = {
    textOutput = PseudoStream.output(textInput) ?: "处理失败"
}){
    Text("Modify")
}
Text(textOutput)

内容的提问来源于stack exchange,提问作者Artaza Sameen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 23:15:03