JNI Environment Pointer

拟墨画扇 提交于 2021-01-27 18:32:09

问题


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(){
    //Code
}

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 env 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());
        android_assert(instance);
        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 JNIEnv variable does not work. Is there any workaround then?


回答1:


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.

Untested:

JavaVM* g_jvm = 0;
JNIEXPORT void JNICALL package_initJNI(JNIEnv* en, jobject ob)
{
    ....
    // insted of the env store the VM
    en->GetJavaVM(&g_jvm);
    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);
}


来源:https://stackoverflow.com/questions/38976639/jni-environment-pointer

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!