1. 程式人生 > >Android jni c/c++線程通過CallVoidMethod調用java函數出現奔潰問題

Android jni c/c++線程通過CallVoidMethod調用java函數出現奔潰問題

== 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函數出現奔潰問題