Подтвердить что ты не робот

Вызов в сохраненный объект Java через JNI из другого потока

У меня есть объект java, который вызывает JNI-объект совместно с С++. В С++ я сохраняю ссылку на JNIEnv и jObject.

JavaVM * jvm;
JNIEnv * myEnv;
jobject myobj;

JNIEXPORT void JNICALL Java_org_api_init
   (JNIEnv *env, jobject jObj) {
    myEnv = env;
    myobj = jObj;
}

У меня также есть средство визуализации GLSurface, и он в конечном итоге вызывает общий объект С++, упомянутый выше, в другом потоке - GLThread. Затем я пытаюсь перезвонить в исходный объект Java, используя исходный файл, который я сохранил изначально, но я думаю, потому что я нахожусь в GLThread, я получаю следующую ошибку.

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

Код, возвращающийся обратно в 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); 

}

Если вместо этого я создаю новый jObject, используя env- > NewObject, я могу успешно вернуться к Java, но это новый объект, и я этого не хочу. Мне нужно вернуться к исходному объекту Java.

Это вопрос переключения потоков, прежде чем я перейду на Java? Если да, то как мне это сделать?

4b9b3361

Ответ 1

Доступ к объекту из разных потоков прекрасен. Проблема в том, что JNI вызывает получение объектов в качестве локальных ссылок. Если вы хотите сохранить ссылку на задание между вызовами JNI, вам необходимо сделать глобальную ссылку:

myobj = env->NewGlobalRef(jObj);

Не забудьте освободить его после того, как вы закончите использовать его, иначе сборщик мусора не будет его собирать, и вы получите утечки памяти:

myEnv->DeleteGlobalRef(myobj);

Ознакомьтесь с глобальными vs локальными ссылками здесь.