Jni本地多線程回調Java函數,env->findClass()失敗。


遇到的問題,Native層本地多線程回調Java函數時env->findClass()失敗。

前面的代碼是這樣的在 JNI_OnLoad記錄全局變量g_vm static JavaVM* g_vm = NULL;

 1 JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)
 2 
 3 {
 4 
 5     JNIEnv * env = NULL;
 6 
 7     if (g_vm == NULL)
 8     {
 9         g_vm = vm;
10     }
11 
12     if (g_vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK)
13     {
14 
15         ALOGD("connot get g_Env is OK ");
16 
17         return JNI_ERR;
18 
19     }
20 
21     return JNI_VERSION_1_4;
22 
23 }

在子線程回調函數中去g_vm->AttachCurrentThread獲取env,通過env去findClass代碼如下這里發現cls == NULL

 1 int nativeCallBackJava(int id)
 2 
 3 {
 4 
 5     jint result;
 6 
 7     JNIEnv * env = NULL;
 8 
 9     if (g_vm == NULL)
10     {
11         return FALSE;
12     }
13 
14     result = (g_vm)->AttachCurrentThread(&env, NULL);
15 
16     if (result != JNI_OK)
17     {
18         return FALSE;
19     }
20 
21     cls = (env)->FindClass("com/lipeng/NativeCallJava");
22 
23     if (cls == NULL)
24     {
25         return FALSE;
26     }
27 
28     mid = (env)->GetStaticMethodID(cls, "nativeNotifyJava", "(I)I");
29 
30     if (mid == NULL)
31     {
32         return FALSE;
33     }
34 
35     (env)->CallStaticIntMethod(cls, mid, id);
36 
37     return TRUE;
38 
39 }

為什么會這樣呢?我並沒有看源碼,覺得子線程AttachCurrentThread得到的env其類的加載器中並沒有去加載自定義的類,所有這里你無法去findClass你自己的類,有人說這里find 系統類env->FindClass("java/lang/String");
這樣是可以的,我沒有做嘗試。

解決方案如下,

Java

1. 需要的類里面有個public native void setClsRef(void);

2. 在初始的時候調用本地函數來設計該類的全局引用

本地Native定義全局引用static jobject g_ObjCall = NULL;

實現setClsRef函數

3.

 1 JNIEXPORT void JNICALL Java_com_lipeng_NativeCallJava_setClsRef(JNIEnv* env, jobject thiz)
 2 
 3 {
 4 
 5     if (g_ObjCall == NULL)
 6     {
 7 
 8         g_ObjCall = env->NewGlobalRef(thiz); //獲取全局引用
 9 
10         if (g_ObjCall == NULL)
11 
12         {
13 
14             ALOGD("get  g_ObjCall == NULL) ");
15 
16         }
17 
18         if (thiz != NULL)
19         {
20 
21             env->DeleteLocalRef(thiz);
22         }//釋放局部對象.這里可不要,調用結束后虛擬機會釋放
23 
24     }

4.調用

 1 int nativeCallBackJava(int id)
 2 
 3     {
 4 
 5         jint result;
 6 
 7         JNIEnv * env = NULL;
 8 
 9         if (g_vm == NULL)
10         {
11             return FALSE;
12         }
13 
14         result = (g_vm)->AttachCurrentThread(&env, NULL);
15 
16         if (result != JNI_OK)
17         {
18             return FALSE;
19         }
20 
21         cls = (env)->GetObjectClass(g_ObjAd); //從全局引用獲取局部對象
22 
23         if (cls == NULL)
24         {
25             return FALSE;
26         }
27 
28         mid = (env)->GetStaticMethodID(cls, "nativeNotifyJava", "(I)I");
29 
30         if (mid == NULL)
31         {
32             return FALSE;
33         }
34 
35         (env)->CallStaticIntMethod(cls, mid, id);
36 
37         env->DeleteLocalRef(cls); //調用完后釋放局部對象,這里是需要的,子線程調用該局部對象不會被虛擬機銷毀,需顯示調用Delete
38 
39         return TRUE;
40 
41     }

這樣就可以在本地多線程隨意使用了,回調Java層了,子線程結束后別忘了 g_vm->DetachCurrentThread()

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM