android JNI层线程回调Java函数
来源:互联网 发布:移动网络e是什么意思 编辑:程序博客网 时间:2024/05/22 15:06
今天,简单讲讲android的jni如何使用jni回调java函数。
之前,我写了部分jni的博客,讲的都是如何从android的java代码调用jni的函数。最近,需要做一个新的功能,在jni的C函数里,需要开一个线程,不停回调java的函数。开始查了很多资料,最终是完成了效果。这里记录一下。
需要调用的java的函数:
/** * * @param datas * @param dataSize * @param sync_code * @param frametype * @param frameno * @param channel * @param tv_sec * @param tv_msec */public void decodeData(byte[] datas, int dataSize ,int sync_code,int frametype,int frameno,int channel,int tv_sec,int tv_msec,int hStream) { }
二.在jni里首先进行回调java函数:
1.首先定义一个保存变量的结构体。
//记录类相关的信息typedef struct ClassInfo { JavaVM *jvm; //保存java虚拟机,这是在新线程中能够回调到java方法的最重要的参数. jobject obj; //保存java对象 jmethodID callbackMethodId; //保存methodID jmethodID receiveDeviceEventId; //保存methodID}ClassInfo;//定义一个全局的ClassInfoClassInfo gClassInfo = {0};
2.对结构体的变量初始化。
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); return 0; }
说明一下初始化的内容,首先通过GetJavaVM获取到java虚拟机,然后通过FindClass获取调用jni的类,这里必须注意一点,就是这里获取的类只能是调用jni的类,不能是其他类。我调用其他的类,出现崩溃问题。然后通过GetMethodID获取java函数。最后,通过NewGlobalRef新建了回调函数所在的类的实体变量。因为我这里回调的函数不是静态函数,所以需要新建实体类。
这里需要注意java函数变量对应的签名,java函数是
public void decodeData(byte[] datas, int dataSize ,int sync_code,int frametype,int frameno,int channel,int tv_sec,int tv_msec,int hStream)
对应的获取函数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:
CallVoidMethodvoidCallObjectMethodjobjectCallBooleanMethodjbooleanCallByteMethodjbyteCallCharMethodjcharCallShortMethodjshortCallIntMethodjintCallLongMethodjlongCallFloatMethodjfloatCallDoubleMethodjdoubleandroid JNI层线程回调Java函数就讲完了。
就这么简单。
- android JNI层线程回调Java函数
- JNI层线程回调Java函数示例
- Android开发实践:JNI层线程回调Java函数示例
- Android开发实践:JNI层线程回调Java函数示例
- Android开发实践:JNI层线程回调Java函数示例
- JNI层线程回调Java函数关键点及示例
- Android jni 回调Java层函数方法
- cocos2d-x 通过JNI实现c/c++和Android的java层函数互调
- cocos2d-x 通过JNI实现c/c++和Android的java层函数互调
- cocos2d-x 通过JNI实现c/c++和Android的java层函数互调
- cocos2d-x 通过JNI实现c/c++和Android的java层函数互调
- 通过JNI实现c/c++和Android的java层函数互调
- cocos2d-x 通过JNI实现c/c++和Android的java层函数互调
- (转)cocos2d-x 通过JNI实现c/c++和Android的java层函数互调
- cocos2d-x 通过JNI实现c/c++和Android的java层函数互调 .
- cocos2d-x 通过JNI实现c/c++和Android的java层函数互调
- cocos2d-x 通过JNI实现c/c++和Android的java层函数互调
- cocos2d-x 通过JNI实现c/c++和Android的java层函数互调
- Java基础 8 包 继承 抽象
- 设计模式基本原则浅析
- 第四章 类图建模(二)
- 创建一个居右只显示在任务区的窗体
- scanf用法总结
- android JNI层线程回调Java函数
- .net多线程控制神器与神坑
- OKHttp上传下载
- maven 3.5.2 以及新的 mvn 不是内部命令 也不是可运行的程序
- 从5千到3万,程序员的成长课
- 如何统计日志里面访问次数最多的IP
- Java基础 9 String 用法
- 科大讯飞语音转文字JSON数据的
- Java基础 10 System,算数