I have a java object which calls into a C++ shared object via JNI. In C++, I am saving a reference to the JNIEnv and jObject.
JavaVM * jvm; JNIEnv * myEnv; jobject myobj; JNIEXPORT void JNICALL Java_org_api_init (JNIEnv *env, jobject jObj) { myEnv = env; myobj = jObj; }
I also have a GLSurface renderer and it eventually calls the C++ shared object mentioned above on a different thread, the GLThread. I am then trying to call back into my original Java object using the jobject I saved initially, but I think because I am on the GLThread, I get the following error.
W/dalvikvm(16101): JNI WARNING: 0x41ded218 is not a valid JNI reference I/dalvikvm(16101): "GLThread 981" prio=5 tid=15 RUNNABLE I/dalvikvm(16101): | group="main" sCount=0 dsCount=0 obj=0x41d6e220 self=0x5cb11078 I/dalvikvm(16101): | sysTid=16133 nice=0 sched=0/0 cgrp=apps handle=1555429136 I/dalvikvm(16101): | schedstat=( 0 0 0 ) utm=42 stm=32 core=1
The code calling back into Java :
void setData() { jvm->AttachCurrentThread(&myEnv, 0); jclass javaClass = myEnv->FindClass("com/myapp/myClass"); if(javaClass == NULL){ LOGD("ERROR - cant find class"); } jmethodID method = myEnv->GetMethodID(javaClass, "updateDataModel", "()V"); if(method == NULL){ LOGD("ERROR - cant access method"); } // this works, but its a new java object //jobject myobj2 = myEnv->NewObject(javaClass, method); //this is where the crash occurs myEnv->CallVoidMethod(myobj, method, NULL);
}
If instead I create a new jObject using env->NewObject, I can succuessfully call back into Java, but it is a new object and I dont want that. I need to get back to my original Java Object.
Is it a matter of switching threads before I call back into Java? If so, how do I do so ?
It allows Java code that runs inside a Java Virtual Machine (VM) to interoperate with applications and libraries written in other programming languages, such as C, C++, and assembly. The most important benefit of the JNI is that it imposes no restrictions on the implementation of the underlying Java VM.
jobject thiz means the this in java class. Sometimes if you create a static native method like this. void Java_MyClass_method1 (JNIEnv *, jclass); jclass means the class itself. Follow this answer to receive notifications.
env : the JNI interface pointer. name : the name of the class or interface to be defined.
JNI is the Java Native Interface. It defines a way for the bytecode that Android compiles from managed code (written in the Java or Kotlin programming languages) to interact with native code (written in C/C++).
Accessing object from different threads is fine. Problem is that JNI calls get objects as local references. If you want to keep reference to jobject between JNI calls you need to make it global reference:
myobj = env->NewGlobalRef(jObj);
Remember to free it after you're done using it otherwise garbage collector won't collect it and you'll get memory leaks:
myEnv->DeleteGlobalRef(myobj);
Read about global vs local references here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With