Android JNI和NDK學習(09)--JNI實例二 傳遞類對象
1 應用層代碼
NdkParam.java是JNI函數的調用類,它的代碼如下:
package com.skywang.ndk; import android.app.Activity; import android.os.Bundle; import android.util.Log; public class NdkParam extends Activity { public static final String TAG="skywang--NdkParam"; /** Called when the activity is first created. */ private Person person=null; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Log.d(TAG, "on create."); person = new Person(); for (int i=0; i<3; i++) { getPersonInfoByIndex(person, i); Log.d(TAG, "person["+i+"] -- "+person); } } // jni中注冊的方法 private native int getPersonInfoByIndex(Person person, int index); static { // 加載本地libndk_load.so庫文件 System.loadLibrary("ndk_param"); } }
Person.java是用來在Java和JNI之間傳遞的數據類,它的代碼如下:
package com.skywang.ndk; public class Person { private String mName; private int mAge; private float mHeight; public String toString(){ return "mName:"+mName+", mAge:"+mAge+", mHeight:"+mHeight; } }
2 JNI層代碼
ndk_param.c是實現並注冊JNI的文件,它的代碼如下:
#include <stdlib.h> #include <string.h> #include <stdio.h> #include <jni.h> #include <assert.h> // 獲取數組的大小 # define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0]))) // 指定要注冊的類,對應完整的java類名 #define JNIREG_CLASS "com/skywang/ndk/NdkParam" #define JNIPAR_CLASS "com/skywang/ndk/Person" // 引入log頭文件 #include <android/log.h> // log標簽 #define TAG "hello_param" // 定義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__) // jfieldID結構體,用於保存類“Person.java”的filedID struct PersonOffsets { jfieldID name; jfieldID age; jfieldID height; } gPersonOffsets; // 與“Person.java”對應的結構體,用於保存數據,並將數據賦值給Person.java的成員 typedef struct tagPerson { char mName[10]; int mAge; float mHeight; }Person; // 定義了3個Person static Person gPersons[] = { {"skywang", 25, 175}, {"eman" , 30, 166}, {"Dan" , 51, 172}, }; #define GPERSON_NUM NELEM(gPersons) /* * 根據index獲取Person信息。 * 參數說明: * env : JNI 接口指針。 * claszz : Java 類對象。 * person : 輸入參數,java對象 * index : 輸入參數,序列號。 */ JNIEXPORT jint JNICALL getPersonInfoByIndex(JNIEnv *env, jobject clazz, jobject person, jint index) { // 若index無效,則直接返回-1。 if ((int)index<0 || (int)index>=GPERSON_NUM) return -1; // 將Person數組(gPersons)中的第index個成員賦值給pPerson指針 Person *pPerson = &gPersons[index]; // 設置java對象person的mName jstring name = (*env)->NewStringUTF(env, pPerson->mName); (*env)->SetObjectField(env, person, gPersonOffsets.name, name); // 設置java對象person的mAge (*env)->SetIntField(env, person, gPersonOffsets.age, pPerson->mAge); // 設置java對象person的mHeight (*env)->SetFloatField(env, person, gPersonOffsets.height, pPerson->mHeight); LOGD("%s index-%d mName:%s, mAge:%d, mHeight:%f\n", __func__, index, pPerson->mName, pPerson->mAge, pPerson->mHeight); return 0; } // 初始化函數,用於獲取Java中各個成員對應的fieldID。 static void nativeClassInit (JNIEnv *env) { jclass personClass = (*env)->FindClass(env, JNIPAR_CLASS); // 獲取Person的mName成員對應的FieldID,並保存到gPersonOffsets中 gPersonOffsets.name = (*env)->GetFieldID(env, personClass, "mName" , "Ljava/lang/String;"); // 獲取Person的mAge成員對應的FieldID,並保存到gPersonOffsets中 gPersonOffsets.age = (*env)->GetFieldID(env, personClass, "mAge" , "I"); // 獲取Person的mHeight成員對應的FieldID,並保存到gPersonOffsets中 gPersonOffsets.height = (*env)->GetFieldID(env, personClass, "mHeight", "F"); } // Java和JNI函數的綁定表 static JNINativeMethod method_table[] = { { "getPersonInfoByIndex", "(Lcom/skywang/ndk/Person;I)I", (void*)getPersonInfoByIndex },//綁定 }; // 注冊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_param(JNIEnv *env) { nativeClassInit(env); // 調用注冊方法 return registerNativeMethods(env, JNIREG_CLASS, method_table, NELEM(method_table)); } // JNI_OnLoad在jni注冊時,會被回調執行。 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_param(env); // 返回jni的版本 return JNI_VERSION_1_4; }
Android.mk的代碼如下:
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := ndk_param LOCAL_SRC_FILES := ndk_param.c # 添加對log庫的支持 LOCAL_LDLIBS:=-L$(SYSROOT)/usr/lib -llog # 若生成static的.a,只需添加 LOCAL_LDLIBS:=-llog include $(BUILD_SHARED_LIBRARY) LOCAL_PATH := $(call my-dir)
3 運行工程
logcat信息如下:
D/skywang--NdkParam: on create. D/hello_param: getPersonInfoByIndex index-0 mName:skywang, mAge:25, mHeight:175.000000 D/skywang--NdkParam: person[0] -- mName:skywang, mAge:25, mHeight:175.0 D/hello_param: getPersonInfoByIndex index-1 mName:eman, mAge:30, mHeight:166.000000 D/skywang--NdkParam: person[1] -- mName:eman, mAge:30, mHeight:166.0 D/hello_param: getPersonInfoByIndex index-2 mName:Dan, mAge:51, mHeight:172.000000 D/skywang--NdkParam: person[2] -- mName:Dan, mAge:51, mHeight:172.0
點擊下載:“源代碼”