Android JNI 传递对象
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");
其中,com/example/helloworld 是包名对应路径,ParamInfo是包含数据接口的类名。
获取类中一个整型变量intValue的定义
jfieldID jfi = env->GetFieldID(jcInfo, "intValue", "I");
获取实例的变量intValue的值,其中jobj即参数中携带数据的对象:
paramInfo.intValue = env->GetIntField(jobj, jfi);
在C代码中设置向Java端传递的参数:
以传递结构体中一个整型值为例:
先设置结构体中整型值:
paramInfo.intValue = 8;
获取Java中的实例类ParamInfo
jclass jcInfo = env->FindClass("com/example/helloworld/ParamInfo");
其中com/example/helloworld 是包名对应路径,ParamInfo是包含数据接口的类名。
获取类中一个整型变量intValue的定义
jfieldID jfi = env->GetFieldID(jcInfo, "intValue", "I");
创建新的对象
jobject joInfo = env->AllocObject(jcInfo);
设置实例的变量intValue的值
env->SetIntField(joInfo, jfi, paramInfo.intValue);
最后返回该对象
return joInfo;
其余数据类型值的访问,都是类似的步骤。注意 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中的实例类ParamInfo
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 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");
最后输出的日志信息:
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下载:
Android JNI 传递对象的更多相关文章
- Android Bundle传递对象
首先Android的Bundle是可以传递对象的.我们可以用Bundle b = new Bundle():b.putSerializable("key", 对象引用); 但是这样 ...
- Android中传递对象的三种方法
Android知识.前端.后端以至于产品和设计都有涉猎,想成为全栈工程师的朋友不要错过! Android中,Activity和Fragment之间传递对象,可以通过将对象序列化并存入Bundle或者I ...
- jni传递对象中包含arraylist对象。
相信在使用jni的过程中,总是要传递各种各样的类型,在这其中,我也碰到了一些问题. 简单的传一些内容,相信在网上一搜一大把. 所以我们就来说说.传递对象中包含arraylist吧. 在这里先给大家一个 ...
- Android JNI 自定义对象为参数和返回值
ndroid JNI 提供了很强大的支持,不仅可以采用基本类型做为参数和返回值,同时也支持自定义对象做为参数和返回值,以下举例说明. 一.定义作为输入和返回的自定义类 (仅提供两个简单类型和一个打印函 ...
- Android Intent传递对象小结
效果: 想看实例的,感兴趣的能够看之前的一篇文章 Android ViewPager Fragment实现选项卡 部分关键代码: public class SerializeActivity exte ...
- Android Intent传递对象摘要
效果: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaG9uZ3NoZW5ncGVuZw==/font/5a6L5L2T/fontsize/400/fil ...
- Android jni 编程(参数的传递,成员,方法的)相互访问
package com.test.androidjni; import android.app.Activity; import android.os.Bundle; import android.u ...
- Android 全局获取 Context 与使用 Intent 传递对象
=====================全局获取 Context======================== Android 开发中很多地方需要用到 Context,比如弹出 Toast.启动活 ...
- Android中如何使用Intent在Activity之间传递对象[使用Serializable或者Parcelable]
http://blog.csdn.net/cjjky/article/details/6441104 在Android中的不同Activity之间传递对象,我们可以考虑采用Bundle.putSeri ...
随机推荐
- Django设计模式
单例模式: 建造者模式: 示例: from enum import Enum import time PizzaProgress = Enum('PizzaProgress', 'queued pre ...
- android拨号
android:textColor="#A0ff1400" A0表示透明度00完全透明FF完全不透明,后面6位是RGB问题:类中类的findViewById方法为何用不了?解:类中 ...
- topcoder srm 400 div1
problem1 link 枚举指数,然后判断是不是素数即可. problem2 link 令$f[len][a][b][r]$(r=0或者1)表示子串$init[a,a+len-1]$匹配$goal ...
- CentOS7下Docker中构建Jenkins容器
背景 在CentOS搭建Docker完成后,我们需要在Docker中搭建Jenkins用来实现工程自动部署. 安装前提 jdk已安装,安装目录如:usr/java/jdk1.8.0_161 maven ...
- Materialize和Material Design Lite的区别
Material Design Lite是google官方库,Materialize是第三方 Material Design Lite不依赖jquery,Materialize依赖jquery Mat ...
- gimp的使用笔记
gimp是德国的开源软件! 跟其他软件一样, 包括file, edit, view, 还有select, color , filter, 和 window. 窗口window就包括所有的dockabl ...
- ASP.NET Core2.1 中如何使用 Cookie和Session
https://blog.csdn.net/canduecho/article/details/80651853 ASP.NET Core2.1的官方项目模板在创建的Razor Pages和MVC项目 ...
- [CodeForces - 276A] Lunch Rush
题目链接:http://codeforces.com/problemset/problem/276/A 从这n个输入中求最大值,注意 和 k的比较,定义一个maxn,对每个输入进行计算即可. AC代码 ...
- Ubuntu fcitx CPU占用率很高解决方法
在Ubuntu中,有时候电脑的风扇突然狂装,用 pidstat -u 5 1 命令查看后台应用的资源占用情况,发现fcitx的占用率接近百分之百. 原因是搜狗云输入的问题,关闭后,在用kill命令干掉 ...
- 今天就整一个bug了
BeanPostProcessor加载次序及其对Bean造成的影响分析 SSM整合出现not found for dependency: expected at least 1 bean which ...