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. fjwc2019 D6T2 密文(trie+贪心)

    #194. 「2019冬令营提高组」密文 设$s[i]$表示前$i$个密文的异或和 容易发现,只要知道$s[0]~s[n](s[0]=0)$就可以知道每一位的值. 转化一下,就变成了在完全图上求最小生 ...

  2. 关于我在17号“一个查询任意年份中任意月份的天数”程序编写中的代码&第二种方法!

    PS:下面的代码是我对于17号的练习题的一些新的看法(其实就是从另一个角度思考问题) package day20180917;import java.util.Scanner;//导包public c ...

  3. Codeforces 37D Lesson Timetable - 组合数学 - 动态规划

    题目传送门 神奇的门I 神奇的门II 题目大意 有$n$组学生要上课2次课,有$m$个教室,编号为$1$到$m$.要确定有多少种不同的安排上课的教室的方案(每组学生都是本质不同的),使得它们满足: 每 ...

  4. uoj 300 [CTSC2017]吉夫特 - Lucas - 分块 - 动态规划

    题目传送门 戳此处转移 题目大意 给定一个长为$n$的序列,问它有多少个长度大于等于2的子序列$b_{1}, b_{2}, \cdots, b_{k}$满足$\prod_{i = 2}^{k}C_{b ...

  5. centos7 挂载磁盘设置开机自启动

    1.首先查看系统磁盘情况: 2.格式化自己想要挂载的磁盘类型(ext3 ext4现在主要使用的是这些) 3.查看自己格式化磁盘的uuid(使用UUID挂载是唯一标识安全) 4.复制UUID号(别复制双 ...

  6. NodeJs完全迁移到D盘,形成绿色安装版

    查看npm配置 D:\Git\AG-Admin-v2. (master) $ npm config ls ; cli configs metrics-registry = "https:// ...

  7. 最大公约数gcd与最小公倍数lcm

    最大公约数:gcd 最大公倍数:lcm gcd和lcm的性质:(我觉得主要是第三点性质) 若gcd (

  8. LuoguP5221 Product

    题目地址 题目链接 题解 注,下方\((i,j)\)均指\(gcd(i,j)\),以及证明过程有一定的跳步,请确保自己会莫比乌斯反演的基本套路. 介绍本题的\(O(n)\)和\(O(n\sqrt{n} ...

  9. 牛客OI周赛7-普及组 解题报告

    出题人好评. 评测机差评. A 救救喵咪 二位偏序.如果数据范围大的话直接树状数组,不过才1000就\(O(n^2)\)暴力就ok了. #include <bits/stdc++.h> s ...

  10. Visual Studio 安装easyX且导入graphics库后,outtextxy提示未定义标示符

    1.点击 “项目” ,然后点击 “属性”. 2. 然后点击左侧 “配置与属性” 下的 “常规” ,在点击 “字符集” ,选择 “使用多字节字符集” 即可解决问题