jni回调android子线程,android JNI层线程回调Java函数

今天,简单讲讲android的jni如何使用jni回调java函数。java

以前,我写了部分jni的博客,讲的都是如何从android的java代码调用jni的函数。最近,须要作一个新的功能,在jni的C函数里,须要开一个线程,不停回调java的函数。开始查了不少资料,最终是完成了效果。这里记录一下。android

须要调用的java的函数:多线程

/****@paramdatas*@paramdataSize*@paramsync_code*@paramframetype*@paramframeno*@paramchannel*@paramtv_sec*@paramtv_msec*/public voiddecodeData(byte[] datas,intdataSize

,intsync_code,intframetype,intframeno,intchannel,inttv_sec,inttv_msec,inthStream) {

}

二.在jni里首先进行回调java函数:jvm

1.首先定义一个保存变量的结构体。函数

//记录类相关的信息typedef structClassInfo {

JavaVM *jvm;//保存java虚拟机,这是在新线程中可以回调到java方法的最重要的参数.jobject obj;//保存java对象jmethodID callbackMethodId;//保存methodIDjmethodID receiveDeviceEventId;//保存methodID}ClassInfo;//定义一个全局的ClassInfoClassInfo gClassInfo = {0};

2.对结构体的变量初始化。

spa

JNIEXPORT jint JNICALL Java_com_p2p_protocol_Protocol_1APIs_initCallBack

(JNIEnv *env,jobject obj){

/***说明:在jni层若是有多线程,实际上JNIEnv(jni环境变量)是不可以在多线程中共用的, env只能在当前线程有效,*可是JavaVM能够,JavaVM指Java虚拟机,这个变量是进程可共用的.因此要想在其余线程中回调java方法,须要保存的是jvm.*/(*env).GetJavaVM(&gClassInfo.jvm);jclass cls = (*env).FindClass("com/p2p/protocol/Protocol_APIs");if(NULL == cls) {

LOGE("can't find jclass:ProtocolCallBack");return-1;}

gClassInfo.callbackMethodId = (*env).GetMethodID(cls,"decodeData","([BIIIIIIII)V");if(NULL == gClassInfo.callbackMethodId) {

LOGE("can't find method ProtocolCallBack from JniClass");return-1;}

gClassInfo.receiveDeviceEventId = (*env).GetMethodID(cls,"receiveDeviceEvent","(II)V");/***说明:为了可以在其它线程获得java的对象,必需要instance转化为全局对象,这样在其它线程才能获得当前java对象的索引.*不然在其它线程要用到当前java对象时,会出现无效引用的错误.*/gClassInfo.obj = (*env).NewGlobalRef(obj);if(NULL == gClassInfo.obj) {

LOGE("can't find jobject");return-1;}

//调用decodeData方法//env->CallVoidMethod(gClassInfo.obj,gClassInfo.callbackMethodId,NULL,10);return0;}

说明一下初始化的内容,首先经过GetJavaVM获取到java虚拟机,而后经过FindClass获取调用jni的类,这里必须注意一点,就是这里获取的类只能是调用jni的类,不能是其余类。我调用其余的类,出现崩溃问题。而后经过GetMethodID获取java函数。最后,经过NewGlobalRef新建了回调函数所在的类的实体变量。由于我这里回调的函数不是静态函数,因此须要新建实体类。线程

这里须要注意java函数变量对应的签名,java函数是code

public voiddecodeData(byte[] datas,intdataSize

,intsync_code,intframetype,intframeno,intchannel,inttv_sec,inttv_msec,inthStream)

对应的获取函数ID的jni是:对象

gClassInfo.callbackMethodId = (*env).GetMethodID(cls,"decodeData","([BIIIIIIII)V");

这个函数签名比较重要,也比较复杂,我会在写一遍博客来说解。索引

具体的讲解以下:

在本地方法中调用Java对象的方法的步骤:

1)获取你须要访问的Java对象的类

FindClass经过传java中完整的类名来查找java的class

GetObjectClass经过传入jni中的一个java的引用来获取该引用的类型。

他们之间的区别是,前者要求你必须知道完整的类名,后者要求在Jni有一个类的引用。

2)获取MethodID,调用方法

GetMethodID 获得一个实例的方法的ID

GetStaticMethodID 获得一个静态方法的ID

3)获取对象的属性

GetFieldID 获得一个实例的域的ID

GetStaticFieldID 获得一个静态的域的ID

JNI经过ID识别域和方法,一个域或方法的ID是任何处理域和方法的函数的必须参数。

3.在线程调用java函数

JNIEnv *env;(*gClassInfo.jvm).AttachCurrentThread(&env,NULL);//调用decodeData方法env->CallVoidMethod(gClassInfo.obj,gClassInfo.callbackMethodId,jbarray,cFrame->cFrameBuffer.dwBufLen,header->dwDataPacketStartCode,header->bytFrameType,header->dwFrameNo,cFrame->dwChannel,header->dwTimestampBySecond,header->dwTimestampByUSecond/1000,hStream);(*gClassInfo.jvm).DetachCurrentThread();

这里首先获取到线程的JNIEnv,而后经过CallVoidMethod调用java的decodeData函数。

具体的调用函数的代码和函数的返回值相关,对应规则以下:

Instance Method Calling Routines:

CallVoidMethod

void

CallObjectMethod

jobject

CallBooleanMethod

jboolean

CallByteMethod

jbyte

CallCharMethod

jchar

CallShortMethod

jshort

CallIntMethod

jint

CallLongMethod

jlong

CallFloatMethod

jfloat

CallDoubleMethod

jdouble

android JNI层线程回调Java函数就讲完了。

就这么简单。





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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值