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
CodePudding user response:
This is not the error caused by JNI , this issue is with how you are passing your TextField value to the jniMethod . The error in the stack trace says :
java.lang.NullPointerException: Parameter specified as non-null is null
.
This means that you are passing null value to the function .
The code works fine as long as I don't modifiy the value inside the TextField
-> This is because you have set the initial value of text_input , so a non-null value is passed ,thus causing no-error .
You need to do the following to correct your error : Just change this line :
text_output.value = PseudoStream.output(text_input.value)
To :
text_output.value = PseudoStream.output(text_input.value.text)
Here you pass the text that you given as an input to the TextField instead of the TextField data class which will do the trick .
To know more about the above said , debug text_input.value
and know your mistake .
CodePudding user response:
I have finally figured out why my app is not working. It has something to do with nullables inside the code logic of recompostion. Since, I have updated my android project to use the stable release of compose. The code is actually working as expected.