我们通常都是在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引用。
网友评论