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++回调的时候直接使用该全局类或函数方法即可

这样类就反射出来了

inflect java_在native线程利用JNI 反射自定义类相关推荐

  1. 利用java反射调用类的的私有方法

    http://blog.csdn.net/sunyujia/article/details/2501709 今天和一位朋友谈到父类私有方法的调用问题,本来以为利用反射很轻松就可以实现,因为在反射看来根 ...

  2. 利用java反射调用类的的私有方法--转

    原文:http://blog.csdn.net/woshinia/article/details/11766567 1,今天和一位朋友谈到父类私有方法的调用问题,本来以为利用反射很轻松就可以实现,因为 ...

  3. 类变量利用Java反射获取类的私有变量值

    这两天笔者几篇文章介绍了改类变量的文章. 关联文章的地址 从计划的准则说来,类的成员变量如果计划成private,那么我们就不能在类外部去获得到此private变量的值.平日的做法是供提此privat ...

  4. android 串口开发第二篇:利用jni实现android和串口通信

    一:串口通信简介 由于串口开发涉及到jni,所以开发环境需要支持ndk开发,如果未配置ndk配置的朋友,或者对jni不熟悉的朋友,请查看上一篇文章,android 串口开发第一篇:搭建ndk开发环境以 ...

  5. Java利用JNI调用c++代码简易例子演示

    点击打开链接 (提取码:8676) 一.首先简单交代一下两个问题: 1.什么是JNI                - - -     JNI的全名为Java Native Interface(Jav ...

  6. android jni 回调 java_android linux线程通过JNI回调java函数 | 学步园

    Linux线程通过JNI回调JAVA函数 最近做的一个小工程需要用到回调函数,由linux层回调到java层,调试的时候会遇到一些问题,免得忘记,在这里记录一下: JNI的各种数据类型和数据结构我就不 ...

  7. java 对象复制 反射_利用Java反射机制实现对象相同字段的复制操作

    一.如何实现不同类型对象之间的复制问题? 1.为什么会有这个问题? 近来在进行一个项目开发的时候,为了隐藏后端数据库表结构.同时也为了配合给前端一个更友好的API接口文档(swagger API文档) ...

  8. Java如何利用JNI调用C++(简略介绍及步骤)

    Java如何利用JNI调用C++(简略介绍及步骤) 文章目录 Java如何利用JNI调用C++(简略介绍及步骤) 一.原理介绍 二.详细步骤 步骤一:编写Java类 步骤二:生成.h文件 步骤三:CL ...

  9. 利用java反射机制 读取配置文件 实现动态类载入以及动态类型转换

    作者:54dabang 在spring的学习过程之中,我们能够看出通过配置文件来动态管理bean对象的优点(松耦合 能够让零散部分组成一个总体,而这些总体并不在意之间彼此的细节,从而达到了真正的物理上 ...

最新文章

  1. html语言技术基础,第2章Web编程基础HTML语言技术方案.ppt
  2. SqlServer学习之触发器
  3. jks与keystore的区别
  4. bupt summer training for 16 #5 ——数据结构
  5. python的csv标准库,Python标准库: csv模块——CSV文件的读写
  6. chrome浏览器 提示Adobe Flash Player未安装的解决方法
  7. Python 如何从字符串中提取 URL 链接
  8. LIBSVM使用方法及参数设置
  9. linux清空日志文件内容 (转)
  10. unity3d游戏开发之UV贴图教程
  11. GB28181 视频服务器文档整理
  12. 教你如何一键批量删除空间说说
  13. 必学技术java Swing之随心所欲添加自定义位置和大小的组件(建议收藏)
  14. 刘顺琦 - CSCI 561 mid 1definition
  15. Descriptors cannot not be created directly
  16. python递归算法 - 汉诺塔问题
  17. CPU、操作系统的32位与64位
  18. OLED模块以及OLED屏幕上显示
  19. 武汉上海知名互联网公司面试心得体会
  20. 2022年下半年软件设计师考试报名时间

热门文章

  1. 运动目标检测--背景减法
  2. pythonfor循环文件写入失败_Python:使用for循环写入文件
  3. Ransomware的斗士——云备份系统
  4. java正则表达式验证标点符号
  5. 非常实用的论文查找网站
  6. CSS3干货23:常用字体样式设置
  7. 印度软件业为什么?把脉中国软件企业
  8. 周易六十四卦——大畜卦
  9. 家族谱树形数据结构实现
  10. 各类型液晶电视面板解析