Android NDK开发(二)数组

来源:互联网 发布:阿里云服务器好用吗 编辑:程序博客网 时间:2024/05/22 03:49

在这篇文章里记录一下C语言操作java数组的相关方法,通过一个简单的程序实现:在c语言里使用java生成的数组,在java里使用c语言生成的数组。

数据类型对应关系


首先我们来看一下,c语言和java语言里数据类型是如何对应的

// 基本类型typedef unsigned char   jboolean;       /* unsigned 8 bits */typedef signed char     jbyte;          /* signed 8 bits */typedef unsigned short  jchar;          /* unsigned 16 bits */typedef short           jshort;         /* signed 16 bits */typedef int             jint;           /* signed 32 bits */typedef long long       jlong;          /* signed 64 bits */typedef float           jfloat;         /* 32-bit IEEE 754 */typedef double          jdouble;        /* 64-bit IEEE 754 */typedef jint            jsize;// 对象类型typedef void*           jobject;typedef jobject         jclass;typedef jobject         jstring;typedef jobject         jarray;typedef jarray          jobjectArray;typedef jarray          jbooleanArray;typedef jarray          jbyteArray;typedef jarray          jcharArray;typedef jarray          jshortArray;typedef jarray          jintArray;typedef jarray          jlongArray;typedef jarray          jfloatArray;typedef jarray          jdoubleArray;typedef jobject         jthrowable;typedef jobject         jweak;

这里只截取与C语言有关的部分,如果想查看全部对应关系,请参考${ndk_dir}/platforms/android-14/arch-arm/usr/include/jni.h

相关方法


1、生成数组

    jobjectArray  (*NewObjectArray)(JNIEnv*, jsize, jclass, jobject);    // 参数第四个参数用来初始化数组(All elements are initially set to initialElement.)    jbooleanArray (*NewBooleanArray)(JNIEnv*, jsize);    jbyteArray    (*NewByteArray)(JNIEnv*, jsize);    jcharArray    (*NewCharArray)(JNIEnv*, jsize);    jshortArray   (*NewShortArray)(JNIEnv*, jsize);    jintArray     (*NewIntArray)(JNIEnv*, jsize);    jlongArray    (*NewLongArray)(JNIEnv*, jsize);    jfloatArray   (*NewFloatArray)(JNIEnv*, jsize);    jdoubleArray  (*NewDoubleArray)(JNIEnv*, jsize);

2、 获取长度

jsize       (*GetArrayLength)(JNIEnv*, jarray);

3、获取数组里的内容

3、1、对象类型的数组

jobject     (*GetObjectArrayElement)(JNIEnv*, jobjectArray, jsize);// 最后一个参数是要获取的对象在数组里的下标

3、2、基本类型数组

    jboolean*   (*GetBooleanArrayElements)(JNIEnv*, jbooleanArray, jboolean*);    jbyte*      (*GetByteArrayElements)(JNIEnv*, jbyteArray, jboolean*);    jchar*      (*GetCharArrayElements)(JNIEnv*, jcharArray, jboolean*);    jshort*     (*GetShortArrayElements)(JNIEnv*, jshortArray, jboolean*);    jint*       (*GetIntArrayElements)(JNIEnv*, jintArray, jboolean*);    jlong*      (*GetLongArrayElements)(JNIEnv*, jlongArray, jboolean*);    jfloat*     (*GetFloatArrayElements)(JNIEnv*, jfloatArray, jboolean*);    jdouble*    (*GetDoubleArrayElements)(JNIEnv*, jdoubleArray, jboolean*);

A family of functions that returns the body of the primitive array. The result is valid until the corresponding ReleaseArrayElements() function is called. Since the returned array may be a copy of the Java array, changes made to the returned array will not necessarily be reflected in the original array until ReleaseArrayElements() is called.
If isCopy is not NULL, then *isCopy is set to JNI_TRUE if a copy is made; or it is set to JNI_FALSE if no copy is made.
PS:第三个参数:JNI_TRUE或者JNI_FALSE或者0
PS:如果我们调用这些方法时没有把数组赋值一份,用完后也需要调用对应的ReleaseArrayElements方法释放资源,否则会内存泄漏。

4、给数组赋值

4、1、对象类型

void        (*SetObjectArrayElement)(JNIEnv*, jobjectArray, jsize, jobject);

4、2、基本数据类型

    void        (*ReleaseBooleanArrayElements)(JNIEnv*, jbooleanArray,                        jboolean*, jint);    void        (*ReleaseByteArrayElements)(JNIEnv*, jbyteArray,                        jbyte*, jint);    void        (*ReleaseCharArrayElements)(JNIEnv*, jcharArray,                        jchar*, jint);    void        (*ReleaseShortArrayElements)(JNIEnv*, jshortArray,                        jshort*, jint);    void        (*ReleaseIntArrayElements)(JNIEnv*, jintArray,                        jint*, jint);    void        (*ReleaseLongArrayElements)(JNIEnv*, jlongArray,                        jlong*, jint);    void        (*ReleaseFloatArrayElements)(JNIEnv*, jfloatArray,                        jfloat*, jint);    void        (*ReleaseDoubleArrayElements)(JNIEnv*, jdoubleArray,                        jdouble*, jint);

最后一个参数:
0——-copy back the content and free the elems buffer
JNI_COMMIT——-copy back the content but do not free the elems buffer
JNI_ABORT——-free the buffer without copying back the possible changes

如果有其他参数不明白什么意思,可以参考http://docs.oracle.com/javase/6/docs/technotes/guides/jni/spec/functions.html#wp9502

sample

1、新建项目,添加native修饰的方法

public class MainActivity extends Activity {    public native int[] testArray(byte[] array);    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);    }}

2、在命令行,cd 到src目录下,执行命令

这里写图片描述

这里写图片描述

3、在项目跟目录下创建jni文件夹,把第二步生成的net_qingtian_array_MainActivity.h头文件拷贝在该目录下。

4、 在jni目录下新建一个c代码源文件,叫array.c,在array.c里把net_qingtian_array_MainActivity.h头文件里的方法给实现了

#include "net_qingtian_array_MainActivity.h"#include <android/log.h>JNIEXPORT jintArray JNICALL Java_net_qingtian_array_MainActivity_testArray  (JNIEnv * env, jobject obj, jbyteArray _jbyteArray){    // 获取数组长度    jsize length = (*env)->GetArrayLength(env, _jbyteArray);    __android_log_print(ANDROID_LOG_INFO, "qingtian", "byte数组长度:%d", length);    // 获取c语言的数组    jbyte* _bytes = (*env)->GetByteArrayElements(env, _jbyteArray, JNI_FALSE);    // 打印数组    int i = 0;    for(i = 0 ; i < length ; i ++){        __android_log_print(ANDROID_LOG_INFO, "qingtian", "byte数组第%d个值:%d", i, _bytes[i]);    }    // 释放byte数组资源    (*env)->ReleaseByteArrayElements(env, _jbyteArray, _bytes, 0);    // 生成jint数组,长度为传递进来的数组的两倍    jsize newLength = length * 2;    jintArray _jintArray = (*env)->NewIntArray(env, newLength);    // 获取jintArray对应的本地数组    jint* _jints = (*env)->GetIntArrayElements(env, _jintArray, JNI_FALSE);    // 赋值    for(i = 0 ; i < newLength ; i ++){        _jints[i] = 20 + i;    }    // 释放int数组资源    (*env)->ReleaseIntArrayElements(env, _jintArray, _jints, 0);    // 返回int数组    return _jintArray;}

5、 在jni下编写Android.mk,这是和编译打包有关系的脚本文件

LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)# 对应打包成函数库的名字LOCAL_MODULE    := array# 对应c代码的文件LOCAL_SRC_FILES := array.cLOCAL_LDLIBS += -lloginclude $(BUILD_SHARED_LIBRARY)

6、编译共享库。在linux环境下切换到项目根目录(cygwin),执行ndk-build命令。

这里写图片描述

7、在java方法里添加调用native方法的代码

public class MainActivity extends Activity {    static {        System.loadLibrary("array");    }    public native int[] testArray(byte[] array);    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        byte[] bytes = new byte[]{0, 1, 2};        int[] ints = testArray(bytes);        Log.d("qingtian", "int数组的长度是:"+ints.length);        for(int i = 0 ; i < ints.length ; i ++){            Log.d("qingtian",  String.format("int数组第%d个值:%d", i, ints[i]));        }    }}

8、运行项目。

这里写图片描述

最后

祝大家元旦快乐。

1 0