Android jni c/c++線程通過CallVoidMethod調用java函數出現奔潰問題
阿新 • • 發佈:2019-03-26
== nat 地方 delete ext new delet cvt getenv
最近在移植網絡攝像機裏的p2p庫到android平臺,需要用到jni,最近在c線程了調用java函數的時候
出現一個問題,假如在同一個線程調用java函數是沒問題的,但在一個c線程了調用java函數就出現奔
潰問題,下面就直接貼c線程裏調用java函數的流程代碼吧:
步驟1. 我這裏的應用是,java處理視頻播放,在java層寫需要調用的函數,例如:
private void recvData(String devid, byte[] data, int nDataType, int nLen){ Log.i(TAG, "recv id:"+devid+", type:"+nDataType+", len:"+nLen); }
步驟2. 在native-lib.cpp中jni層代碼如下(註意這是c++代碼):
JavaVM* local_JavaVM = NULL; jobject j_obj = NULL; jmethodID j_mid = NULL; JNIEXPORT void JNICALL Java_com_p2p_test_MainActivity_InitP2P (JNIEnv *env, jobject jobj) { jclass clazz = env->GetObjectClass(jobj); j_obj= env->NewGlobalRef(jobj);//**這裏是關鍵** //jclass clazz = env->GetObjectClass(jobj);//之前是這樣寫,一直導致奔潰 j_mid = env->GetMethodID(clazz, "recvData", "(Ljava/lang/String;[BII)V"); if(j_mid == NULL) { LOGE("Error GetMethodID"); } } jint JNI_OnLoad(JavaVM* vm, void* reserved) { LOG("JNI_OnLoad"); local_JavaVM = vm ; JNIEnv* env = 0; jint ret = -1; if (vm->GetEnv((void**) &env, JNI_VERSION_1_6) != JNI_OK) { LOGE("JNI_OnLoad error"); goto onLoadError; } ret = JNI_VERSION_1_6; onLoadError: return ret; }
步驟3.我這裏的應用p2p在收到視頻流數據的時候,需要將視頻數據傳送到java層,例如其他c文件xxxxx.c收到視頻數據,在調用CallVoidMethod可以調用java函數(註意這是c代碼)。
extern jmethodID j_mid ; extern jobject j_obj ; extern JavaVM* local_JavaVM; JNIEnv *env; **//這是一個線程** void dataRecvThread() { int ret = 0; int status = (*local_JavaVM)->GetEnv(local_JavaVM, (void **)&(env), JNI_VERSION_1_6); if(status < 0) { status = (*local_JavaVM)->AttachCurrentThread(local_JavaVM, &(env), NULL);//**這是關鍵地方** if(status < 0) { return NULL; } ret= 1; } ..............//接受視頻代碼省略 if(j_obj != NULL && j_mid != NULL) { int nDataType = data.frameType; int nLen = data.len; jstring jdevid = (*env)->NewStringUTF(env, "ARD1W45LKUYHAAAA1E"); jbyteArray jbuff = (*env)->NewByteArray(env, nLen); (*env)->CallVoidMethod(env, j_obj , j_mid , jdevid, jbuff, nDataType, nLen); (*env)->DeleteLocalRef(env, jbuff); (*env)->DeleteLocalRef(env, jdevid); } .............//代碼省略 if(ret) { (*local_JavaVM)->DetachCurrentThread(local_JavaVM); } }
這樣就可以成功調用了
Android jni c/c++線程通過CallVoidMethod調用java函數出現奔潰問題