JNI笔记3,解决findClass()调用失败的问题
以上一篇转载的为例,做具体分析,并且代码调试通过,上一篇转载的文章因转载人数过多,其实代码是跑不起来的。
00 背景
在JNI的调用中,总是要涉及到Native层调用Java层的情况,最近遇到的问题就是,Native层本地多线程回调Java函数时env->findClass()
失败,单线程调用的时候会成功,多线程调用的时候存在返回NULL
的情况。
01 举例
这里使用网上示例为例,
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,通过env去findClass代码如下这里发现cls == NULL
int nativeCallBackJava(int id)
{
jint result = -1;
JNIEnv * env = NULL;
if(g_vm == NULL) return FALSE;
result = (g_vm)->AttachCurrentThread(&env, NULL);
if(result != JNI_OK) {return FALSE;}
jclass cls = (env)->FindClass("com/lipeng/NativeCallJava");
if(cls == NULL) {return FALSE;}
jmethodID mid = (env)->GetStaticMethodID( cls, "nativeNotifyJava","(I)I");
if(mid == NULL) {return FALSE;}
(env)->CallStaticIntMethod( cls, mid, id);
return TRUE;
}
02 解决方法
- 需要的类里面有个
public native void setClsRef(void);
- 在初始的时候调用本地函数来设计该类的全局引用.
代码如下,使用的大概是网上一个帖子的例子,但由于转载的人太多了,其实代码是跑不起来的,所以这里特意进行了调试修正,这个例子使用直接关联的方式调用,楼主实际过程中喜欢用动态函数注册的方式调用Native函数。
static jobject g_ObjCall= NULL;
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);}//释放局部对象.这里可不要,调用结束后虚拟机会释放
}
void nativeCallBackJava(int id)
{
jint result = -1;
bool isAttached = false;
JNIEnv *env = NULL;
if(g_ptrJavaVM == NULL) return;
int32_t status = g_ptrJavaVM->GetEnv((void**)&env, JNI_VERSION_1_4);
if (status < 0) {
result = g_ptrJavaVM->AttachCurrentThread((void**)&env, nullptr);
if(result != JNI_OK){
ALOGE("AttachCurrentThread failed!");
return;
}
isAttached = true;
}
jmethodID mid = NULL;
jclass cls = (env)->GetObjectClass(g_ObjCall);
if(cls == NULL){
/* error handing */
ALOGE("GetObjectClass failed!");
goto err;
}
mid = (env)->GetStaticMethodID(cls, "eventNativeCallback", "(Ljava/lang/String;I)V");
if(mid == NULL){
/* error handing */
ALOGE("GetStaticMethodID failed!");
env->DeleteLocalRef(cls);
goto err;
}
(env)->CallStaticVoidMethod(cls, mid, id);
env->DeleteLocalRef(cls);
err:
if (isAttached) {
g_ptrJavaVM->DetachCurrentThread();
}
}