本博客主要是在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編譯,運行即可。