JNI 中,JNIEnv*指针变量只对当前线程有效。如果是其他的线程,需要先获得 JVM*指针,然后再获得当前线程的JNIEnv*指针。部分示例代码为:
/** Invoker.cpp, Invoker.java */
#include <jni.h>
#include <stdio.h>
#include "Invoker.h"
#include "invoker_include.h"
JavaVM * jvm;
JNIEnv * static_env;
jobject * jObject; //线程间公用,必须使用 global reference
jclass c; //必须使用 global reference
jmethodID m; //必须使用 global reference
/*****************************
* Class: Invoker
* Method: register
* Signature: ()V
*****************************/
JNIEXPORT void JNICALLJava_Invoker_register (JNIEnv *env, jobject arg)
{
jObject = arg;
// printf("object: %x, %x. \n", &arg,&jObject);
printf("[main] Invoker registered.\n");
jclass bgpClass =(*env)->GetObjectClass(env, arg);
jmethodID methodId =(*env)->GetMethodID(env, bgpClass, "invoke", "()V");
printf("[main] -class: %d, method: %d\n", bgpClass, methodId);
(*env)->CallVoidMethod(env, arg,methodId);
// Global reference
(*env)->GetJavaVM(env, &jvm);
jObject =(*env)->NewGlobalRef(env, arg);
c =(*env)->NewGlobalRef(env, bgpClass);
m =(*env)->NewGlobalRef(env, methodId);
start(invoke_java_method);
(*env)->DeleteGlobalRef(env,c); //手动销毁 global reference
(*env)->DeleteGlobalRef(env,m); //手动销毁 global reference
(*env)->DeleteGlobalRef(env, jObject);
(*jvm)->DetachCurrentThread(jvm); //销毁线程
(*jvm)->DestroyJavaVM(jvm); //?销毁虚拟机
}
// Test method
JNIEXPORT void JNICALL Java_Invoker_println(JNIEnv *env, jobject obj, jstring string)
{
const char *str =(*env)->GetStringUTFChars(env, string, 0);
printf("[main] %s\n",str);
(*env)->ReleaseStringUTFChars(env,string, str);
}
// Callback method回调函数
int invoke_java_method ()
{
(*jvm)->AttachCurrentThread(jvm,(void**)&static_env, 0); //获得当前线程可以使用的 JNIEnv *指针
(*static_env)->CallVoidMethod(static_env, jObject, m); //调用 Java 方法
printf("[callback] java methodinvoked, invoker class: %x ... \n", &jObject);
}