听闻少年二字,当与平庸相斥。这篇文章主要讲述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");
- 1
- 获取类中一个整型变量intValue的定义
jfieldID jfi = env->
GetFieldID(jcInfo, "intValue", "I");
- 1
- 获取实例的变量intValue的值,其中jobj即参数中携带数据的对象:
paramInfo.intValue = https://www.songbingjia.com/android/env->
GetIntField(jobj, jfi);
- 1
- 先设置结构体中整型值:
paramInfo.intValue = https://www.songbingjia.com/android/8;
- 1
- 获取Java中的实例类ParamInfo
jclass jcInfo = env->
FindClass("com/example/helloworld/ParamInfo");
- 1
- 获取类中一个整型变量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
请查看下表:
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 (参数类型)返回类型 |
// 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 = https://www.songbingjia.com/android/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);
intnArrLen = 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=https://www.songbingjia.com/android/%d, paramInfo.charValue=%c/n",
paramInfo.array, paramInfo.boolValue, paramInfo.charValue);
LOGI("paramInfo.doubleValue=https://www.songbingjia.com/android/%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 = https://www.songbingjia.com/android/true;
paramInfo.charValue = ‘B‘;
paramInfo.doubleValue = 2.7182;
paramInfo.intValue = 8;
strcpy(paramInfo.str,"Hello from JNI");
LOGI("paramInfo.array=%s, paramInfo.boolValue=https://www.songbingjia.com/android/%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;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
// 动态加载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 = https://www.songbingjia.com/android/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="https://www.songbingjia.com/android/+ paramInfoGet.boolValue
+" paramInfoGet.charValue="https://www.songbingjia.com/android/+ paramInfoGet.charValue
+" paramInfoGet.doubleValue="https://www.songbingjia.com/android/+ paramInfoGet.doubleValue);
Log.i("Hello", "log: paramInfoGet.intValue="https://www.songbingjia.com/android/+ 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
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
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=https://www.songbingjia.com/android/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
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
demo下载:http://download.csdn.net/detail/lintax/9559413
推荐阅读
- 理解Angular中的$apply()以及$digest()
- Android Studio Gradle优化方法
- Android-性能优化之布局优化
- elasticsearch index 之 Mapping
- 如何在Ubuntu 20.04上安装和使用Docker(分步指南)
- Docker特权模式(你应该运行特权Docker容器吗())
- 如何在Ubuntu 20.04上安装和配置Ansible(分步指南)
- 10个Docker安全最佳技巧和提示介绍
- 如何在Git上取消暂存文件(详细操作介绍)