Android jni c/c++线程通过CallVoidMethod调用java函数出现奔溃问题
最近在移植网络摄像机里的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); } }
这样就可以成功调用了