Why jni calls fail on modification of composable remembered values?

This is my PseudoStream class which interfaces with C++

class PseudoStream{
    companion object{
        // This native function receives a String as a Input and returns a Modified output
        external fun output(input: String): String
    }
}

This is the C++ Inteface code to for the output function

// Creates a jstring from a std::string passed as mystr

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

// Converts a jstring to std::string and returns it

std::string jstringtostring(JNIEnv *env, jstring jStr) {
    if(!jStr)
        return "";

       const jclass stringClass = env->GetObjectClass(jStr);
       const jmethodID getBytes = env->GetMethodID(stringClass, "getBytes", "(Ljava/lang/String;)[B");
       const jbyteArray stringJbytes = (jbyteArray) env->CallObjectMethod(jStr, getBytes, env->NewStringUTF("UTF-8"));

       size_t length = (size_t) env->GetArrayLength(stringJbytes);
       jbyte* pBytes = env->GetByteArrayElements(stringJbytes, NULL);

       std::string ret = std::string((char *)pBytes, length);
       env->ReleaseByteArrayElements(stringJbytes, pBytes, JNI_ABORT);

       env->DeleteLocalRef(stringJbytes);
       env->DeleteLocalRef(stringClass);
       return ret;
}

// This is the actual function called by jni to modify the String

extern "C"
JNIEXPORT jstring JNICALL
Java_com_phantom_automath_PseudoStream_00024Companion_output(JNIEnv *env, jobject thiz, jstring input) {
    std::string expression = jstringtostring(env, input);
    return Create_Java_String(env, expression + " (Modified by C++)");
}

Now, this code is the main UI code


var text_input = remember {mutableStateOf("Initial value ")} // Used by the TextField for Input
var text_output = remember {mutableStateOf("")} // Used by Text() for modified output

TextField(
    value = text_input.value,
    onValueChange = { text_input.value = it },
)

Button(onClick = {
        // The jni method is called here
        text_output.value = PseudoStream.output(text_input.value)
        }
    ){
    Text("Modify")
}

Text(text_output.value) // Displays the output by the jni call

So here is my problem, Whenever I click the Modify Button without changing the initial value of the TextField. The code works as expected. But, once I modify the TextField and then click Modify Button again this runtime error occurs in kotlin code.

java.lang.NullPointerException: Parameter specified as non-null is null: method kotlin.jvm.internal.Intrinsics.checkNotNullParameter, parameter interactionSource
        at androidx.compose.foundation.ClickableKt.clickable(Unknown Source:7)
        at androidx.compose.foundation.ClickableKt.clickable$default(Clickable.kt:112)
        at androidx.compose.material.ButtonKt.Button(Button.kt:117)

The code works fine as long as I don’t modifiy the value inside the TextField

Source: Windows Questions C++

LEAVE A COMMENT