我們通常都是在C++主線程中調用java方法,很簡單,但是在子線程中調用java方法卻不能採用在主線程中調用的方式,因爲調用java方法是要用JNIEnv去調用的,但是JNIEnv是線程相關的,子線程中不能直接使用創建線程的JNIEnv,所以需要JVM進程相關的,可以通過JVM來獲取當前線程的JNIEnv,然後就可以調用java方法了。
#include "JavaListener.h"
JavaListener::JavaListener(JavaVM *vm, _JNIEnv *env, jobject obj) {
this->jvm = vm;
this->jenv = env;
this->jobj = obj;
jclass clz = env->GetObjectClass(jobj);
if(!clz){
return;
}
jmid = env->GetMethodID(clz,"onError","(ILjava/lang/String;)V");
}
/**
*調用java方法
* @param type 0:子線程,1:主線程
* @param code
* @param msg
*/
void JavaListener::onError(int type, int code, const char *msg) {
if(type == 0){
JNIEnv *env;
//初始化當前線程的JNIEnv
jvm->AttachCurrentThread(&env,0);
jstring jmsg = env->NewStringUTF(msg);
env->CallVoidMethod(jobj,jmid,code,jmsg);
env->DeleteLocalRef(jmsg);
//釋放當前線程的引用
jvm->DetachCurrentThread();
}else if(type == 1){
jstring jmsg = jenv->NewStringUTF(msg);
jenv->CallVoidMethod(jobj,jmid,code,jmsg);
jenv->DeleteLocalRef(jmsg);
}
}
pthread_t thread;
//子線程執行體
void *normalCallBack(void *data){
LOG("Create C++ normal thread!");
pthread_exit(&thread);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_xy_jni_jnithreaddemo_feature_JniThread_createNormalThread(JNIEnv *env, jobject instance) {
//創建子線程
pthread_create(&thread,NULL,normalCallBack,NULL);
}
#include "JavaListener.h"
JavaVM *jvm;
//初始化JavaVM
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm,void* reserved){
JNIEnv *env;
jvm = vm;
if(vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6) != JNI_OK){
return -1;
}
return JNI_VERSION_1_6;
}
extern "C"
JNIEXPORT void JNICALL
Java_com_xy_jni_jnithreaddemo_feature_JniThread_callbackJavaFromC(JNIEnv *env, jobject instance) {
javaListener = new JavaListener(jvm,env,env->NewGlobalRef(instance));
//主線程中調用
// javaListener->onError(1,100,"c++ call java meid from main thread!");
//開啓子線調用
pthread_create(&child_thread,NULL,childCallback,javaListener);
}
主要步驟就是,通過運行時函數JNI_OnLoad初始化JavaVM,再通過JavaVM調用AttachCurrentThread函數初始化當前線程的JNIEnv,此時這個JNIEnv就可以調用java方法了,調用完後要調用JavaVM的DetachCurrentThread函數來釋放JavaVM引用。