jni 传递java对象_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

其中,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中的实例类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");

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下载:

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值