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;
}
  • 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

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
  • 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=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

可以看出,java设置的数值,已经成功传递到C端;而C程序设置的数据,也成功回传到java端了。

demo下载:

http://download.csdn.net/detail/lintax/9559413

时间: 2024-10-24 13:25:50

Android JNI 传递对象的相关文章

Android Intent传递对象小结

效果: 想看实例的,感兴趣的可以看之前的一篇文章 Android ViewPager Fragment实现选项卡 部分关键代码: public class SerializeActivity extends Activity implements Serializable { Button btnlist, btnParcelable, btnSerialze; private final String TAG = "SerializeActivity"; public final s

Android中传递对象的三种方法

Android知识.前端.后端以至于产品和设计都有涉猎,想成为全栈工程师的朋友不要错过! Android中,Activity和Fragment之间传递对象,可以通过将对象序列化并存入Bundle或者Intent中进行传递,也可以将对象转化为JSON字符串,进行传递. 序列化对象可以使用Java的Serializable的接口.Parcelable接口.转化成JSON字符串,可以使用Gson等库. 1.Serializable Model public class Author implement

android 中传递对象两种方法探索(Serializable,Parcelable)

相信大家在android开发的过程中总会遇到要在Activity中间传递数据的情况,当然,遇到需要在Intent中传递对象的情况也不可避免,所以我就so了一下相关的知识,在这里总结消化一下.就目前来说,我了解到的只有两种方式: 1.利用Bundle.putSerializable(Key,Object): 2.利用Bundle.putParcelable(Key, Object): 下面详细介绍两种方法的使用和区别: 首先第一点,这两种方法实现的前提都需要将传递的对象Object序列化,那么,问

Android intent 传递对象以及返回刷新

之前项目需要,找过这方面知识.所以今天也总结一下.大家都知道activity跳转用intent,Android的当前页面跳转到新的页面.当然跳转的同时常常要携带数据或者对象.那我下面就说说跳转带对象吧.还有在例子当中,新的activity返回时,也有对象一起返回.下面看代码,只要入门Android了都看得懂,我就不再写很多注释了. demo源码例子下载地址:点击此处下载 有两种对象类型可以传递,一是Parcelable,推荐用这个.二是Serializable.当然你在class建立对象时,都要

Android Intent传递对象为什么要序列化?

为什么?    a.永久性保存对象,保存对象的字节序列到本地文件中 b.对象可以在网络中传输 c.对象可以在IPC之间传递(进程间通信) 那选哪个序列化? 1)在使用内存的时候,Parcelable比Serializable性能高,所以推荐使用Parcelable. 2)Serializable在序列化的时候会产生大量的临时变量,从而引起频繁的GC. 3)Parcelable不能使用在要将数据存储在磁盘上的情况,因为Parcelable不能很好的保证数据的持续性在外界有变化的情况下.尽管Seri

Android Intent传递对象和集合

Article article = JsonUtils.getArticle(content); intent = new Intent(activity, CompositionCorrect.class); Bundle bundle = new Bundle(); bundle.putSerializable("ARTICLE", article); intent.putExtras(bundle); startActivity(intent); 获取传递的对象 private

Android Intent传递对象摘要

效果: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaG9uZ3NoZW5ncGVuZw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" > 想看实例的,感兴趣的能够看之前的一篇文章 Android ViewPager Fragment实现选项卡 部分关键代码: public class SerializeActivity extends

Android之Activity之间传递对象

在很多时候,我们需要在Activity之间传递对象,比如当你点击了某列表的item,需要传递给下一个Activity该对象,那我们需要该怎么做呢? Android支持两种传递对象的方式,一种是bundle.putSerializable方式,一种是bundle.putParcelable. 那么下面我们就用一个例子来实践Activity传递对象: 1.首先建立两个类,一个Teacher类表示老师,一个Student类表示学生.内容分别如下: <span style="font-size:1

Android中的Parcel机制 实现Bundle传递对象

Android中的Parcel机制    实现了Bundle传递对象    使用Bundle传递对象,首先要将其序列化,但是,在Android中要使用这种传递对象的方式需要用到Android Parcel机制,即,Android实现的轻量级的高效的对象序列化和反序列化机制. JAVA中的Serialize机制,译成串行化.序列化……,其作用是能将数据对象存入字节流当中,在需要时重新生成对象.主要应用是利用外部存储设备保存对象状态,以及通过网络传输对象等.        Android中的新的序列