JNI初步入门后,在传递数据的时候,遇到一个需求:有多个数据需要在Java与C代码之间进行传递。如果都做为函数参数传入,则函数很长很难看,并且多个数据的返回也不好实现。所以想到了把数据打包后传递。这在C语言中就是结构体,在Java中就是类了。
我们要做的工作就是,先确定要传递的数据,然后相应在C与Java中定义相应的数据类型,然后通过JNI进行数据对应。下面以一个例程来逐步说明。

为了更好的说明各种数据类型的转换示例,我们的数据包含整型、字符串、浮点数、字符、布尔值、数组。

在Java端定义类:

public class ParamInfo {public boolean boolValue;public char charValue; public double doubleValue; public int intValue; public byte[] array; public String str; }

在C端定义结构体:

typedef struct{bool boolValue;char charValue;double doubleValue; int intValue; char array[255]; char str[255]; }ParamInfo;

jni接口中并不要求两边的变量名一致,或者类名与结构体名一致,只是我们为了逻辑清晰,最好将名称定义的一致,以便于在后续编写代码的过程中更好的将相应数据一一对应起来。

在C代码中获取Java代码传递的参数:

  • 以获取类中一个整型值为例:
    //获取Java中的实例类ParamInfo
    jclass jcInfo = env->FindClass("com/example/helloworld/ParamInfo");
  • 1

其中,com/example/helloworld 是包名对应路径,ParamInfo是包含数据接口的类名。

  • 获取类中一个整型变量intValue的定义
    jfieldID jfi = env->GetFieldID(jcInfo, "intValue", "I");
  • 1
  • 获取实例的变量intValue的值,其中jobj即参数中携带数据的对象:
    paramInfo.intValue = env->GetIntField(jobj, jfi);
  • 1

在C代码中设置向Java端传递的参数:

以传递结构体中一个整型值为例:

  • 先设置结构体中整型值:
paramInfo.intValue = 8;
  • 1
  • 获取Java中的实例类ParamInfo
    jclass jcInfo = env->FindClass("com/example/helloworld/ParamInfo");
  • 1

其中com/example/helloworld 是包名对应路径,ParamInfo是包含数据接口的类名。

  • 获取类中一个整型变量intValue的定义
   jfieldID jfi = env->GetFieldID(jcInfo, "intValue", "I");
  • 1
  • 创建新的对象
 jobject joInfo = env->AllocObject(jcInfo);
  • 1
  • 设置实例的变量intValue的值
env->SetIntField(joInfo, jfi, paramInfo.intValue);
  • 1
  • 最后返回该对象
return joInfo;
  • 1

其余数据类型值的访问,都是类似的步骤。注意 GetFieldID()的第3个参数的取值,是数据类型的签名标识,具体取值见下面表格:

请查看下表:

Java类型 符号
boolean Z
byte B
char C
short S
int I
long L
float F
double D
void V
object对象 LClassName; L类名;
Arrays [array-type [数组类型
methods方法 (argument-types)return-type (参数类型)返回类型

native代码

知道这些了,就可以进行我们native代码的书写了,如下:

// Java 类向C结构体类型转换
JNIEXPORT jint JNICALL Java_com_example_helloworld_JniClient_setInfo(JNIEnv *env, jobject jo, jobject jobj)
{ParamInfo paramInfo;//获取Java中的实例类ParamInfojclass jcInfo = env->FindClass("com/example/helloworld/ParamInfo"); //获取类中每一个变量的定义 //boolean boolValue jfieldID jfb = env->GetFieldID(jcInfo, "boolValue", "Z"); //char charValue jfieldID jfc = env->GetFieldID(jcInfo, "charValue", "C"); //double charValue jfieldID jfd = env->GetFieldID(jcInfo, "doubleValue", "D"); //int intValue jfieldID jfi = env->GetFieldID(jcInfo, "intValue", "I"); //byte[] array jfieldID jfa = env->GetFieldID(jcInfo, "array", "[B"); //String str jfieldID jfs = env->GetFieldID(jcInfo, "str", "Ljava/lang/String;"); //获取实例的变量boolValue的值 paramInfo.boolValue = env->GetBooleanField(jobj, jfb); //获取实例的变量charValue的值 paramInfo.charValue = env->GetCharField(jobj, jfc); //获取实例的变量doubleValue的值 paramInfo.doubleValue = env->GetDoubleField(jobj, jfd); //获取实例的变量intValue的值 paramInfo.intValue = env->GetIntField(jobj, jfi); //获取实例的变量array的值 jbyteArray ja = (jbyteArray)env->GetObjectField(jobj, jfa); int nArrLen = env->GetArrayLength(ja); char *chArr = (char*)env->GetByteArrayElements(ja, 0); memcpy(paramInfo.array, chArr, nArrLen); //获取实例的变量str的值 jstring jstr = (jstring)env->GetObjectField(jobj, jfs); const char* pszStr = (char*)env->GetStringUTFChars(jstr, 0); strcpy(paramInfo.str, pszStr); //日志输出 LOGI("paramInfo.array=%s, paramInfo.boolValue=%d, paramInfo.charValue=%c\n", paramInfo.array, paramInfo.boolValue, paramInfo.charValue); LOGI("paramInfo.doubleValue=%lf, paramInfo.intValue=%d, paramInfo.str=%s\n", paramInfo.doubleValue, paramInfo.intValue, paramInfo.str); return 0; } // C结构体类型向Java 类转换 JNIEXPORT jobject JNICALL Java_com_example_helloworld_JniClient_getInfo (JNIEnv *env, jobject jo) { char chTmp[] = "Test array"; int nTmpLen = strlen(chTmp); //将C结构体转换成Java类 ParamInfo paramInfo; memset(paramInfo.array, 0, sizeof(paramInfo.array)); memcpy(paramInfo.array, chTmp, strlen(chTmp)); paramInfo.boolValue = true; paramInfo.charValue = 'B'; paramInfo.doubleValue = 2.7182; paramInfo.intValue = 8; strcpy(paramInfo.str, "Hello from JNI"); LOGI("paramInfo.array=%s, paramInfo.boolValue=%d, paramInfo.charValue=%c\n", paramInfo.array, paramInfo.boolValue, paramInfo.charValue); //获取Java中的实例类 jclass jcInfo = env->FindClass("com/example/helloworld/ParamInfo"); //获取类中每一个变量的定义 //boolean boolValue jfieldID jfb = env->GetFieldID(jcInfo, "boolValue", "Z"); //char charValue jfieldID jfc = env->GetFieldID(jcInfo, "charValue", "C"); //double doubleValue jfieldID jfd = env->GetFieldID(jcInfo, "doubleValue", "D"); //int intValue jfieldID jfi = env->GetFieldID(jcInfo, "intValue", "I"); //byte[] array jfieldID jfa = env->GetFieldID(jcInfo, "array", "[B"); //String str jfieldID jfs = env->GetFieldID(jcInfo, "str", "Ljava/lang/String;"); //创建新的对象 jobject joInfo = env->AllocObject(jcInfo); //给类成员赋值 env->SetBooleanField(joInfo, jfb, paramInfo.boolValue); env->SetCharField(joInfo, jfc, (jchar)paramInfo.charValue); env->SetDoubleField(joInfo, jfd, paramInfo.doubleValue); env->SetIntField(joInfo, jfi, paramInfo.intValue); //数组赋值 jbyteArray jarr = env->NewByteArray(nTmpLen); jbyte *jby = env->GetByteArrayElements(jarr, 0); memcpy(jby, paramInfo.array, nTmpLen); env->SetByteArrayRegion(jarr, 0, nTmpLen, jby); env->SetObjectField(joInfo, jfa, jarr); //字符串赋值 jstring jstrTmp = env->NewStringUTF(paramInfo.str); env->SetObjectField(joInfo, jfs, jstrTmp); return joInfo; }

Java端测试代码:

        // 动态加载C库System.loadLibrary("HelloWorld");//进行对象的jni传递ParamInfo paramInfoSet = new ParamInfo();       byte[] b = new byte[10]; for (int i = 0; i < 9; i++) { b[i] = (byte) (i + 97); } paramInfoSet.array = b; paramInfoSet.boolValue = false; paramInfoSet.charValue = 'C'; paramInfoSet.doubleValue = 3.14; paramInfoSet.intValue = 2016; paramInfoSet.str = "Hello from Java"; Log.i("Hello", "log: to access lib"); JniClient.setInfo(paramInfoSet); Log.i("Hello", "log: after setInfo"); //进行对象的jni接收 ParamInfo paramInfoGet = JniClient.getInfo(); Log.i("Hello", "log: paramInfoGet.boolValue=" + paramInfoGet.boolValue + " paramInfoGet.charValue=" + paramInfoGet.charValue + " paramInfoGet.doubleValue=" + paramInfoGet.doubleValue); Log.i("Hello", "log: paramInfoGet.intValue=" + paramInfoGet.intValue + " paramInfoGet.array=" + new String (paramInfoGet.array) + " paramInfoGet.str=" + paramInfoGet.str); //将收到的字符串显示到界面上 TextView tv_say_hello = (TextView) findViewById(R.id.tv_say_hello); tv_say_hello.setText(paramInfoGet.str); Log.i("Hello", "log: finish");
  • 1

最后输出的日志信息:

06-25 17:04:25.740: I/Hello(19039): log: to access lib 06-25 17:04:25.740: I/logfromc(19039): paramInfo.array=abcdefghi, paramInfo.boolValue=0, paramInfo.charValue=C 06-25 17:04:25.740: I/logfromc(19039): paramInfo.doubleValue=3.140000, paramInfo.intValue=2016, paramInfo.str=Hello from Java 06-25 17:04:25.740: I/Hello(19039): log: after setInfo 06-25 17:04:25.740: I/logfromc(19039): paramInfo.array=Test array, paramInfo.boolValue=1, paramInfo.charValue=B 06-25 17:04:25.740: I/Hello(19039): log: paramInfoGet.boolValue=true paramInfoGet.charValue=B paramInfoGet.doubleValue=2.7182 06-25 17:04:25.740: I/Hello(19039): log: paramInfoGet.intValue=8 paramInfoGet.array=Test array paramInfoGet.str=Hello from JNI 06-25 17:04:25.740: I/Hello(19039): log: finish

可以看出,java设置的数值,已经成功传递到C端;而C程序设置的数据,也成功回传到java端了。

demo下载:

http://download.csdn.net/detail/lintax/9559413

转载于:https://www.cnblogs.com/Free-Thinker/p/6829136.html

Android JNI 传递对象相关推荐

  1. android bundle 对象,Android Bundle传递对象

    首先Android的Bundle是可以传递对象的.我们可以用Bundle b = new Bundle():b.putSerializable("key", 对象引用); 但是这样 ...

  2. 如何通过JNI传递对象执行回调

    如何通过JNI传递对象执行回调 JNI的全称是java native interface,用来调用某些特定于系统平台或者硬件的操作,但是它只能调用c/c++的代码,若是其它语言代码,只能通过c/c++ ...

  3. Android中传递对象的三种方法

    Android中,Activity和Fragment之间传递对象,可以通过将对象序列化并存入Bundle或者Intent中进行传递,也可以将对象转化为JSON字符串,进行传递. 序列化对象可以使用Ja ...

  4. android中返回刷新,Android intent 传递对象以及返回刷新

    之前项目需要,找过这方面知识.所以今天也总结一下.大家都知道activity跳转用intent,Android的当前页面跳转到新的页面.当然跳转的同时常常要携带数据或者对象.那我下面就说说跳转带对象吧 ...

  5. android handler 传递对象,Android之Handler消息传递机制详解

    前言 在Android开发中,多线程应用是非常频繁的,其中Handler机制随处可见. 下面就本人对Handle的一些理解与大家一起分享,共同回顾下Handle异步消息传递机制. 1.Handler是 ...

  6. android webservice 传递对象,Android通过ksoap2传递复杂数据类型及CXF发布的webservice详细介绍...

    Android通过ksoap2传递复杂数据类型及CXF发布的webservice详细介绍 最近在学校搞点东西,搞了2天的webservice,心累呀,今天中午和小伙伴终于弄通了,感觉就是一些细节问题没 ...

  7. Android AIDL 传递对象(Parceable),深度解读Netty

    import xj.musicserver.MusicInfo; interface IPlayListener { /** Demonstrates some basic types that yo ...

  8. android sendmessage传递对象,android handler sendMessage

    我们先从最熟悉也是最基本的方法sendMessage(Message msg)来查看,为什么说它是最基本的方法,因为其他发送方法无论是post开头的各种方法还是sendEmptyMessage()本质 ...

  9. android 使用intent传递对象,Android--Intent传递对象

    Intent 传递对象通常有两种实现方式,Serializable 和 Parcelable: 一.Serializable:序列化,表示将一个对象转换成可存储或可传输的状态,序列化后的对象可以在网络 ...

最新文章

  1. 解决Visual Studio For Mac Restore失败的问题
  2. BZOJ4241 历史研究(莫队)
  3. linux看门狗树莓派,给树莓派安装看门狗
  4. python画切片图_python切片操作
  5. 图解Java多线程设计模式
  6. ObjC学习10-Foundation框架之内存管理
  7. iNeedle系统之国舜项目
  8. 计算机的神奇小游戏,电脑课我们常玩的13个小游戏
  9. SparkStreaming可视化之Wisp
  10. 阿里云账号企业实名认证和个人实名认证区别详解
  11. 上帝视角学JAVA- 基础08-类06【2021-08-07】
  12. 中科院30m地表精细土地利用数据Arcgis预处理——入门(二)
  13. 生成子空间的交空间与和空间
  14. 牛客网 - [牛客假日团队赛5]金币馅饼(dp)
  15. 中国纹身针市场趋势报告、技术动态创新及市场预测
  16. 关于Kaggle竞赛
  17. 3盏灯和3个开关的对应关系
  18. 如何实现应用之间的跳转(ios和安卓)
  19. 浏览器的多进程与js单线程
  20. java 自动行高,20191012——POI设置单元格自动行高(思路)

热门文章

  1. Android Studio快捷键——编辑篇
  2. rewirte 规则
  3. 2015总结 2016展望
  4. C#正则表达式提取HTML中IMG标签的SRC地址(转)
  5. Asp.Net异常:由于代码已经过优化或者本机框架位于调用堆栈之上,无法计算表达式的值的解决方法...
  6. 运用家居收纳储物空间 小空间变出大身材
  7. VC++分析数据包实现Telnet协议分析
  8. Visual Studio 2010Beta与Silverlight的更新
  9. jQuery学习笔记——事件
  10. redis cluster 集群重新启动关闭