JNI笔记3,解决findClass()调用失败的问题

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();
	}
 }

你可能感兴趣的:(Android&&底层)