LBes LBes - 2 months ago 5x
C++ Question

JNI Environment Pointer

I have a Java class in which I have a function which must be called from my C code.
The function is the following:

public void endTrial(){

So I have created the following code in my C file:

JNIEXPORT void JNICALL package_endTrialJava();
JNIEXPORT void JNICALL package_endTrialJava(){
jobject javaObjectRef = env->NewObject(javaClassRef, javaMethodRef);
env->CallVoidMethod(javaObjectRef, javaMethodRef);

But to be able to call this function with the
variable, I have created this function which is called whenever I launch my program.

JNIEXPORT void JNICALL package_initJNI(JNIEnv* en, jobject ob)
try {
// LOGD("(JNI) [FluidMechanics] loadVelocityDataSet()");

if (!App::getInstance())
throw std::runtime_error("init() was not called");

if (App::getType() != App::APP_TYPE_FLUID)
throw std::runtime_error("Wrong application type");

FluidMechanics* instance = dynamic_cast<FluidMechanics*>(App::getInstance());
jclass dataClass = en->FindClass("fr/limsi/ARViewer/MainActivity");
javaClassRef = (jclass) env->NewGlobalRef(dataClass);
javaMethodRef = env->GetMethodID(javaClassRef, "endTrial", "()V");

env = en ;
obj = ob ;

} catch (const std::exception& e) {
throwJavaException(env, e.what());

And I have these global variables declared in my code as well, so that the call to initJNI() can store the JNIEnv variable.

JNIEnv* env ;
jobject obj ;

But my program crashed so it seems that storing the
variable does not work. Is there any workaround then?


You cannot/should not store the JNIEnv pointer. Is is only valid for the current thread.
But you can use AttachCurrentThread to get a JNIEnvpointer for your current thread.
Or if you know that it is already attached you can use GetEnv.
And beside of that you do not mention how you use the global jobject obj but keep in mind that you need to take care that those references stay valid long enough. NewGlobalRef is the way to go.


JavaVM* g_jvm = 0;
JNIEXPORT void JNICALL package_initJNI(JNIEnv* en, jobject ob)
    // insted of the env store the VM
    obj = en->NewGlobalRef(ob); // I don't think you need this
    // and at some point you must delete it again

JNIEXPORT void JNICALL package_endTrialJava(){
    JNIEnv* env;
    g_jvm->AttachCurrentThread(&env, NULL); // check error etc
    jobject javaObjectRef = env->NewObject(javaClassRef, javaMethodRef);
    // this line makes not much sense. I think you don't need it if you use the global
    // with the global it would be more like this
    env->CallVoidMethod(obj javaMethodRef);