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 传递对象的更多相关文章

  1. Android Bundle传递对象

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

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

    Android知识.前端.后端以至于产品和设计都有涉猎,想成为全栈工程师的朋友不要错过! Android中,Activity和Fragment之间传递对象,可以通过将对象序列化并存入Bundle或者I ...

  3. jni传递对象中包含arraylist对象。

    相信在使用jni的过程中,总是要传递各种各样的类型,在这其中,我也碰到了一些问题. 简单的传一些内容,相信在网上一搜一大把. 所以我们就来说说.传递对象中包含arraylist吧. 在这里先给大家一个 ...

  4. Android JNI 自定义对象为参数和返回值

    ndroid JNI 提供了很强大的支持,不仅可以采用基本类型做为参数和返回值,同时也支持自定义对象做为参数和返回值,以下举例说明. 一.定义作为输入和返回的自定义类 (仅提供两个简单类型和一个打印函 ...

  5. Android Intent传递对象小结

    效果: 想看实例的,感兴趣的能够看之前的一篇文章 Android ViewPager Fragment实现选项卡 部分关键代码: public class SerializeActivity exte ...

  6. Android Intent传递对象摘要

    效果: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaG9uZ3NoZW5ncGVuZw==/font/5a6L5L2T/fontsize/400/fil ...

  7. Android jni 编程(参数的传递,成员,方法的)相互访问

    package com.test.androidjni; import android.app.Activity; import android.os.Bundle; import android.u ...

  8. Android 全局获取 Context 与使用 Intent 传递对象

    =====================全局获取 Context======================== Android 开发中很多地方需要用到 Context,比如弹出 Toast.启动活 ...

  9. Android中如何使用Intent在Activity之间传递对象[使用Serializable或者Parcelable]

    http://blog.csdn.net/cjjky/article/details/6441104 在Android中的不同Activity之间传递对象,我们可以考虑采用Bundle.putSeri ...

随机推荐

  1. PXC备份方式总结

    记录一下. 1.mysqldump数据导出 关于GTID: GTID是MySQL5.6以后,加入了全局事务 ID (GTID) 来强化数据库的主备一致性,故障恢复,以及容错能力. A global t ...

  2. java配置xml报cvc-complex-type.2.3: 元素 'beans' 必须不含字符 [子级], 因为该类型的内容类型为“仅元素”

    今天测试es-job的时候,启动的时候报了标题中的错误, 经查,原因有二: 一:从网上粘贴过来字符没有对应上,所以子元素property报错,将文字复制到Notepad++等编辑工具,转为UTF-8编 ...

  3. spring @Value注解#和$区别

    一直以来,在使用@Value注解的时候,都是使用#的风格@Value("#{topic.topicName}"),但是也经常会看到@Value("${topic.topi ...

  4. Codeforces 822D My pretty girl Noora - 线性筛 - 动态规划

    In Pavlopolis University where Noora studies it was decided to hold beauty contest "Miss Pavlop ...

  5. ODAC(V9.5.15) 学习笔记(九)TOraSQLMonitor

    名称 类型 说明 Active Boolean 激活SQL跟踪 DBMonitorOptions 将跟踪信息发送到dbMonitor工具软件的选择项 Host IP地址 Port 端口号 Reconn ...

  6. CSS层叠样式表--找到标签

    0 怎么学习CSS 1 CSS的四种引入方式 2 CSS的四种基本选择器 3 属性选择器 4 CSS伪类 5 CSS选择器优先级 6 CSS的继承性 怎么学习CSS 1.怎么找到标签(CSS选择器) ...

  7. SQL 基础语法笔记教程整理

    最近从图书馆借了本介绍 SQL 的书,打算复习一下基本语法,记录一下笔记,整理一下思路,以备日后复习之用. PS:本文适用 SQL Server2008 语法. 首先,附一个发现的 MySQL 读书笔 ...

  8. linux内核中的IPIs是什么?

    答: 处理器间中断(Interprocessor Interrupts)

  9. GCD与莫比乌斯反演的勾当

    目录 机房最后一个学懵逼钨丝的人 题目一 题目 bzoj1101 机房最后一个学懵逼钨丝的人 题目一 链接 题目没找到 求\(\sum_{1}^{n}\sum_{1}^{m}gcd(i,j)\) 式子 ...

  10. MySql 语句收集

    目录 =与:=区别 序列号: 分组: 子查询分组: 同数据库表数据迁移 存储过程 参考: =与:=区别 = 只有在set和update时才是和:=一样,赋值的作用,其它都是等于的作用.鉴于此,用变量实 ...