Android ndk 线程回调java层方法

项目上刚好要在ndk层使用线程回调java层方法,仅以此文做个总结。

线程使用pthread创建(在此略过),线程会循环调用NofityDataCB函数:

static JavaVM* s_jVM = NULL;
static jobject s_jobj = NULL; //java object
static jmethodID s_jcallback = NULL; //方法id

static void NotifyDataCB(unsigned char flag, int x, int y, int w, int h, unsigned char* buff, mp_i64 timeStamp)
{
	//LOG_DBG("[NotifyDataCB()] enter.");
	JNIEnv* env;

	s_jVM->AttachCurrentThread(&env, NULL);	//获取当前线程的JNIEnv*

	env->CallVoidMethod(s_jobj, s_jcallback, ...); //调用java层相关方法

	s_jVM->DetachCurrentThread();	//释放当前线程的JNIEnv*

	//LOG_DBG("[NotifyDataCB()] done.");
	return;
}
此处的重点即为:

jint AttachCurrentThread(JavaVM *vm, void **p_env, void *thr_args);

Attaches the current thread to a Java VM. Returns a JNI interface pointer in the JNIEnv argument.

其中s_jVM是由JNI_OnLoad方法保存而来的;


s_jobj在自定义的jni方法里赋值,并创建了个全局引用,使其不被虚拟机释放

s_jobj = env->NewGlobalRef(thiz); //thiz为jni方法的参数,表示java层的类对象

该s_jobj需要手动释放:

env->DeleteGlobalRef(s_jobj);

s_jcallback也是在自定义的jni方法调用以下方法保存而来:
static jmethodID GetClassMethodID(JNIEnv* env)
{
	jclass clazz = env->FindClass(classPathName); //classPathName完整的包名加类名
	if (clazz == NULL)
	{
		LOG_ERR("[GetClassMethod()]Failed to find jclass");
		return NULL;	
	}


	jmethodID jcallback = env->GetMethodID(clazz, "OnNativeDataCB", "(BIIII[IJ)V"); //获取java层方法id
	if (jcallback == NULL)
	{
		LOG_ERR("[GetClassMethod()]Failed to find method OnNativeDataCB");
		return NULL;	
	}
	
	return jcallback; //返回保存为s_jcallback
}

综上所述,关键步骤为:

1. 在onload的时候保存JavaVM指针。

2. 在自定义jni方法里(该方法须在callback方法使用前调用,例如初始化方法)保存callback方法所在对象,
    且该对象需要创建一个全局引用以便在线程方法里使用,默认是local ref,函数执行完会被虚拟机释放;
    另外自定义jni方法和callback方法在同一个类里,所以在调用自定义方法时能保存一致的jobject  。

3. 也是在自定义jni方法中,通过class获得该callback的method ID。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值