定制Android系统开发之八——实现从JNI到Java的回调
来源:互联网 发布:天狮多种vb片功效 编辑:程序博客网 时间:2024/06/01 09:24
前面已经实现了APP->xxxManager->xxxManagerService->jni的函数调用,这篇博文就来实现jni->xxxManagerService的回调。
使用环境
我先说一下我的应用环境吧。我在有一个对设备节点进行轮询的线程,当能读到消息的时候就调用jni中的一个回调函数。回调函数会调用java中的函数来传递消息。
函数定义
JNI中回调函数的声明如下:
get_msg_cb(message *evtmsg)
它的参数是一个结构体,我在回调函数里将解析这个结构体,转化成int数组。再调用下面的Java函数:
private void recvMsgFromNative(int[] msg)
JNIEnv的对象
但凡做过JNI开发,都会知道,在调用JNI函数的时候,一个JNIEnv指针是必须具备的。在从Java调用的JNI函数的参数列表里面,第一个参数就是一个JNIEnv指针。但是对于我的get_msg_cb()函数,是从底层回调的,没有这个JNIEnv指针,该怎么办呢?
在JNI中,JNIEnv指针是与线程一一对应的,也就是说,每个线程都有一个JNIEnv,在线程一里不能使用线程二的JNIEnv。所以在register_android_server_iflytek_radiomanagerservice里面把JNIEnv保存在一个全局变量中,然后在get_msg_cb()函数里面使用,是不行的。但是,有一个对象却是全局的,那就是JavaVM。我们可以将JavaVM保存在全局变量中,然后通过JavaVM在get_msg_cb()里面获取JNIEnv指针。
static JavaVM * gJavaVM;int register_android_server_radiomanagerservice(JNIEnv* env) { // 此处省略很多行 // 获取JavaVM指针,保存在全局变量里面。 env->GetJavaVM(&gJavaVM); return 0;}
获取对象和函数的引用
Java中的非static函数是属于某个对象的,要想调用这个函数,就必须拥有这个对象的引用。我在Java里面定义了一个nativeInit()函数,并按照上一篇博文的方法映射到jni中的nativeInit()函数。在RadioManagerService()的构造函数里调用nativeInit()函数。在NativeInit()函数里面,通过JNIEnv和jobject获取了RadioManagerService对象的实例并保存在了全局变量中。同时还获取了recvMsgFromNative()函数的ID并保存在全局变量中。代码如下:
static jobject gRadioManagerServiceObj;static jclass gRadioManagerServiceClass;static void nativeInit(JNIEnv* env, jobject obj) { ALOGD("nativeInit() is called"); mcu_rpc_init(); // 获取UartManagerService对象的实例 gRadioManagerServiceObj = env->NewGlobalRef(obj); // Callbacks FIND_CLASS(gRadioManagerServiceClass, "com/android/server/RadioManagerService"); GET_METHOD_ID(gRadioManagerServiceClassInfo.recvMsgFromNative, gRadioManagerServiceClass, "recvMsgFromNative", "([I)V"); // 注册回调 mcu_rpc_set_callback(get_msg_cb);}
JNI函数的实现
下面就是JNI函数的实现了。这里直接给出代码:
void get_msg_cb(message *evtmsg) { ALOGD("get_msg_cb() is called"); int i; // 通过JavaVM获取JNIEnv指针 JNIEnv* env; gJavaVM->AttachCurrentThread(&env, NULL); if (env == NULL) { ALOGD("JNIEnv is null"); return; } // 从message结构体获取数组 jintArray returnArray = getArrayFromMsg(env, evtmsg); // 调用Java中的函数 if (gRadioManagerServiceObj != NULL) { env->CallVoidMethod(gRadioManagerServiceObj, gRadioManagerServiceClassInfo.recvMsgFromNative, returnArray); } // 这里的returnArray是在getArrayFromMsg()函数中通过env->NewIntArray()新建出来的,所以必须delete掉,以释放空间,不然会有内存泄露 env->DeleteLocalRef(returnArray); checkAndClearExceptionFromCallback(env, __FUNCTION__); }
- 定制Android系统开发之八——实现从JNI到Java的回调
- 定制Android系统开发之六——系统服务JNI的实现分析
- 定制Android系统开发之七——跟我实现系统服务的JNI调用
- 定制Android系统开发之九——在系统服务中实现回调
- 定制Android系统开发之四——系统服务实现的分析
- 定制Android系统开发之十——优化系统服务中的回调
- 定制Android系统开发之三——跟着我实现系统服务
- 定制Android系统开发之三——跟着我实现系统服务(测试可用)
- 定制Android系统开发之二——系统服务
- 定制Android系统开发之二——系统服务
- Android 开发 之 JNI入门 - NDK从入门到精通
- Android 开发 之 JNI入门 - NDK从入门到精通
- Android 开发 之 JNI入门 - NDK从入门到精通
- Android 开发 之 JNI入门 - NDK从入门到精通
- Android 开发 之 JNI入门 - NDK从入门到精通
- Android 开发 之 JNI入门 - NDK从入门到精通
- Android 开发 之 JNI入门 - NDK从入门到精通
- Android 开发 之 JNI入门 - NDK从入门到精通
- SpringMVC自定义属性编辑器
- oocss ; LESS;SASS
- POJ 3648 Wedding 2-sat输出一组解
- SpringMVC上传文件
- 导航菜单
- 定制Android系统开发之八——实现从JNI到Java的回调
- jenkins定时构建
- 4.6 总结
- memcached简介及java使用方法
- Xcode遇到了诡异开发问题
- ArcMap无法创建新样式,或将符号添加到样式
- cocosjs显示跨域图片的办法
- jQuery Mobile移动网站开发
- 使用http协议访问svn