Android JNI和NDK學習(09)--JNI實例二 傳遞類對象
阿新 • • 發佈:2017-05-09
get state 回調 obj utf 說明 called [] code
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
點擊下載:“源代碼”
Android JNI和NDK學習(09)--JNI實例二 傳遞類對象