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萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章