在native线程利用JNI 反射自定义类
来源:互联网 发布:贴图绘制软件 编辑:程序博客网 时间:2024/06/06 03:53
NDK编程中遇到的一些细节问题,希望对大家有帮助
-----题记
在JNI中,有时候出于业务要求需要实现异步事件机制,例如网络通讯的收发
这时就会在C++中回调java类的方法,于是就会用到java反射机制
在JNI中,实现类反射主要用到以下几个方法:(本例以反射静态方法为例)
JavaVM jint GetEnv(void **penv, jint version)
JavaVM jint AttachCurrentThread(void **penv, void *args)
JNIEnv jclass FindClass(const char *name)
JNIEnv jmethodID GetStaticMethodID(jclass clazz, const char *name, const char *sig)
JNIEnv void CallStaticVoidMethod(jclass cls, jmethodID methodID, ...)
JavaVM jint DetachCurrentThread()
假设我们要反射的类是:
- package com.genius.test;
- public class InflectClass {
- public static void test(int cmd,String value,String data){
- }
- }
那么C++中回调的JNI代码就是:
- void testInflect(int cmd, const char* value, const char* data)
- {
- if (g_vm == NULL)
- {
- return ;
- }
- int status;
- JNIEnv *env = NULL;
- bool isAttach = false;
- status = g_vm->GetEnv((void **) &env, JNI_VERSION_1_4);
- if(status != JNI_OK)
- {
- status = g_vm->AttachCurrentThread(&env, NULL);
- if(status < 0) {
- return;
- }
- isAttach = true;
- }
- jstring valueString = NULL;
- jstring dataString = NULL;
- jclass inflectClass = NULL;
- jmethodID inflectMethod = NULL;
- jclass inflectClass = env->FindClass("com/genius/test/InflectClass");
- if (inflectClass == NULL)
- {
- return;
- }
- jmethodID inflectMethod= env->GetStaticMethodID(inflectClass, "test", "(ILjava/lang/String;Ljava/lang/String;)V");
- if (inflectMethod == NULL)
- {
- return ;
- }
- valueString = env->NewStringUTF(value);
- dataString = env->NewStringUTF(data);
- env->CallStaticVoidMethod(inflectClass, inflectMethod, cmd, valueString, dataString);
- end:
- if (env->ExceptionOccurred())
- {
- env->ExceptionDescribe();
- env->ExceptionClear();
- }
- if (isAttach)
- {
- g_vm->DetachCurrentThread();
- }
- env->DeleteLocalRef(dataString);
- }
其中g_vm是全局的虚拟机实例,可以在
- JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved);
函数中保存该实例
jint GetEnv(void **penv, jint version)是获取当前线程对应的JNI环境指针
在JNI中,多线程间JNIEnv 是不可以共享的,所以不能全局保存使用
获取是有可能失败的,比如当前是native线程
何为native线程?即在jni中开启的线程。
而java线程则是调用native方法的宿主线程,可以是主线程也可以是子线程
在获取失败时,调用jint AttachCurrentThread(void **penv, void *args)来将当前线程附加到虚拟机并获取JNI环境指针
之后就是通过
jclass FindClass(const char *name)
GetStaticMethodID(jclass clazz, const char *name, const char *sig)
void CallStaticVoidMethod(jclass cls, jmethodID methodID, ...)
来获取类方法并调用
GetStaticMethodID方法的第三个参数是函数签名
主要是c++中重载函数的存在使得函数名不能作为区别函数方法的唯一标示
这时就需要区别参数列表,获取函数签名的命令是javap
具体使用方法大家百度一下就知道了
最后如果有附加当前线程到虚拟机的话
需要调用DetachCurrentThread方法来释放线程
否则线程不能正常结束
温馨提示:
理论上通过上面几个步骤就可以反射到java层了
但实际操作起来会发现在native线程里执行FindClass的时候会找不到该自定义类(系统类可以)
具体原因不详,解决方案如下:
在JNI_OnLoad里获取该类对象并保存一个全局引用
- JavaVM *g_vm = NULL;
- jclass g_inflectClass = NULL;
- jmethodID g_methodID = NULL;
- void InitInflectClass(JavaVM* vm)
- {
- g_vm = vm;
- JNIEnv *env = NULL;
- int status = g_vm->GetEnv((void **) &env, JNI_VERSION_1_4);
- if(status != JNI_OK)
- {
- return ;
- }
- jclass inflectClass = env->FindClass("com/genius/test/InflectClass");
- if (inflectClass == NULL)
- {
- return ;
- }
- g_inflectClass = inflectClass;
- g_methodID = env->GetStaticMethodID(inflectClass, "test", "(ILjava/lang/String;Ljava/lang/String;)V");
- if (g_methodID == NULL)
- {
- return ;
- }
- }
- 直接把函数方法保存下来也可以
然后在C++回调的时候直接使用该全局类或函数方法即可
- 在native线程利用JNI 反射自定义类
- 在native线程利用JNI 反射自定义类
- 在native线程利用JNI 反射自定义类--ndk开发参考2
- android利用JNI调用C++自定义类
- android利用JNI调用C++自定义类
- android利用JNI调用C++自定义类
- android利用JNI调用C++自定义类
- 自定义BaseServlet利用反射
- 利用自定义消息在VC内进行线程间通讯
- Java反射&JNI[Java Native Interface](5.28)
- JNI官方文档翻译7-Java线程和Native线程
- JNI 在native方法中打印日志
- 在Native里面开始线程
- JNI实例2---扫描SD卡中mp3文件,native层调用Java自定义的类
- JNI实例3---扫描SD卡中mp3文件,native层调用Java自定义的类
- JNI加载Native Library 以及 跨线程和Qt通信
- JNI加载Native Library 以及 跨线程和Qt通信
- jni 线程函数调用技巧-native thread exited without detaching
- 使用qml 实现简单的播放器(4)
- 如何检查系统是否支持Zend Optimizer
- cocos2d-x初探学习笔记--物理引擎box2d(1)
- Qt之QComboBox(基本应用、代理设置)
- office 2010 去除页眉横线,以及只去除第一页页眉横线
- 在native线程利用JNI 反射自定义类
- UIView的深入研究
- JVM 调优
- Yarn 2.2.0 未解决问题记录
- Android中的线程小结
- 准确定位程序Crash时所对应的源代码行(三)
- UI第2课UILable第3课自动换行
- 求一个字符串中的两个子串的乘积是否为a的种类数(和顺序有关)
- OpenCV成长之路(4):图像直方图