Jni本地多线程回调Java函数,env->findClass()失败。

遇到的问题,Native层本地多线程回调Java函数时env->findClass()失败。

前面的代码是这样的在 JNI_OnLoad记录全局变量g_vm static JavaVM* g_vm = NULL;

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)

{

JNIEnv * env = NULL;

if(g_vm == NULL){g_vm = vm;}

if( g_vm->GetEnv((void**)&env,JNI_VERSION_1_4) != JNI_OK ){

ALOGD("connot get g_Env is OK ");

return JNI_ERR;

}

return JNI_VERSION_1_4;

}

子线程回调函数中去g_vm->AttachCurrentThread获取env,通过envfindClass代码如下这里发现cls  ==  NULL

int  nativeCallBackJava(int id)

{

jint result;

JNIEnv * env  =  NULL;

if(g_vm  ==  NULL){return FALSE;}

result  =  (g_vm)->AttachCurrentThread(&env, NULL);

if(result  !=  JNI_OK) {return FALSE;}

cls =  (env)->FindClass("com/lipeng/NativeCallJava");

if(cls == NULL) {return FALSE;}

mid = (env)->GetStaticMethodID( cls, "nativeNotifyJava","(I)I");

if(mid == NULL) {return FALSE;}

(env)->CallStaticIntMethod( cls, mid, id);

return TRUE;

}

为什么会这样呢?我并没有看源码,觉得子线程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. JNIEXPORT void JNICALL Java_com_lipeng_NativeCallJava_setClsRef(JNIEnv* env, jobject thiz)

{

if(g_ObjCall == NULL){

g_ObjCall = env->NewGlobalRef(thiz);//获取全局引用

if(g_ObjCall == NULL)

{

ALOGD("get  g_ObjCall == NULL) ");

}

if(thiz != NULL){

env->DeleteLocalRef(thiz);}//释放局部对象.这里可不要,调用结束后虚拟机会释放

 }

4. 调用

int  nativeCallBackJava(int id)

{

jint result;

JNIEnv * env  =  NULL;

if(g_vm  ==  NULL){return FALSE;}

result  =  (g_vm)->AttachCurrentThread(&env, NULL);

if(result  !=  JNI_OK) {return FALSE;}

cls = (env)->GetObjectClass(g_ObjAd);//从全局引用获取局部对象

if(cls == NULL) {return FALSE;}

mid = (env)->GetStaticMethodID( cls, "nativeNotifyJava","(I)I");

if(mid == NULL) {return FALSE;}

(env)->CallStaticIntMethod( cls, mid, id);

env->DeleteLocalRef(cls);//调用完后释放局部对象,这里是需要的,子线程调用该局部对象不会被虚拟机销毁,需显示调用Delete

return TRUE;

}

这样就可以在本地多线程随意使用了,回调Java层了,子线程结束后别忘了 g_vm->DetachCurrentThread()

你可能感兴趣的:(android,C++)