zoukankan      html  css  js  c++  java
  • 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()

  • 相关阅读:
    最小生成树与Prim算法
    图的存储——链式前向星
    *转载 Tarjan有向图详解
    图的连通性算法-Kosaraju
    最小花费8597
    PDF提取图片(错误纠正)
    字符串删除指定符号(不限位置)
    python迭代有限制,突破限制
    storm资源冲突
    storm单节点问题(转载)
  • 原文地址:https://www.cnblogs.com/fnlingnzb-learner/p/7559948.html
Copyright © 2011-2022 走看看