C++子线程调用Java方法

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

发布了94 篇原创文章 · 获赞 40 · 访问量 11万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章