Android NDK 学习之接受Java传入Object数组

本博客主要是在Ubuntu 下开发,且默认你已经安装了Eclipse,Android SDK, Android NDK, CDT插件。

在Eclipse中添加配置NDK,路径如下Eclipse->Window->Preferences->Android->NDK ,选择NDK的路径,然后Apply即可。

新建一个名为AndroidJNI_ObjectArray的Android工程,新建一个jni的文件夹,其目录下文件树列表如下:

├── jni
│   ├── Android.mk
│   ├── Application.mk
│   └── objectarray
│      ├── Android.mk
│      ├── logger.h
│      └── objectarray_jni.c

 

jni/Application.mk文件内容如下:

APP_ABI := all

jni/Android.mk,主要用来指定顺序执行所有子文件夹下面的makefile文件,内容如下:

include $(call all-subdir-makefiles)

 

jni/objectarray/Android.mk,主要用来指定需要编译出的动态库的名称,以及需要编译的源文件,内容如下:

复制代码
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE     := objectarray_jni
LOCAL_SRC_FILES := objectarray_jni.c

LOCAL_LDLIBS := -llog

include $(BUILD_SHARED_LIBRARY)
复制代码

 

jni/objectarray/logger.h 主要用来在JNI层打印日志,内容如下:

复制代码
#include <jni.h>
#include <android/log.h>

/**
 * 定义log标签
 */
#define TAG "jni_logger"

/**
 * 定义info信息
 */
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)

/**
 * 定义debug信息
 */
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)

/**
 * 定义error信息
 */
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
复制代码

 

jni/objectarray/objectarray_jni.c,主要用来注册绑定java函数和native函数,以及java函数在c中相应函数的具体实现, 内容如下:

复制代码
#include "logger.h"

#ifndef NULL
#define NULL   ((void *) 0)
#endif

/**
 * 获取数组的大小
 */
#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))

/**
 * 指定要注册的类,对应的完整的java类名
 */
#define JNIREG_CLASS "com/clarck/jni/MainActivity"

/**
 * 返回jobjectArray对象
 */
JNIEXPORT jobjectArray JNICALL native_initInt2DArray(JNIEnv *env, jobject obj,
        jint size) {
    jobjectArray result;
    int i;

    //得到一个二维 int 类型数组的元素类型的引用
    jclass intArrCls = (*env)->FindClass(env, "[I");
    if (intArrCls == NULL) {
        return NULL;
    }

    //分配一个数组,数组元素类型被用"intArrCls"类型引用来指示。 "NewObjectArray"函数只分配了第一个维度,我们剩下构建二维来填充数组元素任务。
    //Java 虚拟机没有为多维数组指定特定的数据结构。一个二维的数组是一个简单的数组的数组
    result = (*env)->NewObjectArray(env, size, intArrCls, NULL);
    if (result == NULL) {
        return NULL;
    }

    for (i = 0; i < size; i++) {
        jint tmp[256];
        jint j;
        //分配了各个数组的元素
        jintArray iarr = (*env)->NewIntArray(env, size);
        if (iarr == NULL) {
            return NULL;
        }

        for (j = 0; j < size; j++) {
            tmp[j] = i + j;
        }
        //复制"temp[] buffer"的内容到新分配的一维数组中
        (*env)->SetIntArrayRegion(env, iarr, 0, size, tmp);
        //第 i 个一维数组的第 j 个元素值是"i+j"
        (*env)->SetObjectArrayElement(env, result, i, iarr);
        //确保虚拟器不会用光被用来持有 JNI 参考例如"iarr"的内存
        (*env)->DeleteLocalRef(env, iarr);
    }
    return result;
}

/**
 * Java和JNI函数绑定
 */
static JNINativeMethod method_table[] = {
        { "initInt2DArray", "(I)[[I", (void*) native_initInt2DArray },
};

/**
 * 注册native方法到java中
 */
static int registerNativeMethods(JNIEnv* env, const char* className,
        JNINativeMethod* gMethods, int numMethods) {
    jclass clazz;
    clazz = (*env)->FindClass(env, className);
    if (clazz == NULL) {
        return JNI_FALSE;
    }

    if ((*env)->RegisterNatives(env, clazz, gMethods, numMethods) < 0) {
        return JNI_FALSE;
    }

    return JNI_TRUE;
}

/**
 * 调用注册方法
 */
int register_ndk_load(JNIEnv* env) {
    return registerNativeMethods(env, JNIREG_CLASS, method_table,
            NELEM(method_table));
}

JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
    JNIEnv* env = NULL;
    jint result = -1;

    if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) {
        return result;
    }

    register_ndk_load(env);

    //返回jni的版本
    return JNI_VERSION_1_4;
}
复制代码

 

接着在Project中右键Android Tools->Add Native Support,最后java层调用如下:

复制代码
package com.clarck.jni;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        int[][] i2arr = initInt2DArray(3);
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                Log.d("Test", "arr elements: " + i2arr[i][j]);
            }
        }
    }
    
    public native int[][] initInt2DArray(int size);
    
    static {
        System.loadLibrary("objectarray_jni");
    }
}
复制代码

 

接着执行Ctrl+B编译,运行即可。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章