Android NDK 學習之傳遞類對象

本博客主要是在Ubuntu 下開發,且默認你已經安裝了Eclipse,Android SDK, Android NDK, CDT插件。java

在Eclipse中添加配置NDK,路徑以下Eclipse->Window->Preferences->Android->NDK ,選擇NDK的路徑,而後Apply便可。android

新建一個名爲AndroidJNI_Object的Android工程,新建一個jni的文件夾,其目錄下文件樹列表以下:數組

├── jni
│   ├── Android.mk
│   ├── Application.mk
│   └── object
│      ├── Android.mk
│      ├── logger.h
│      └── object_jni.capp

jni/Application.mk文件內容以下:ide

APP_ABI := all

jni/Android.mk,主要用來指定順序執行全部子文件夾下面的makefile文件,內容以下:函數

include $(call all-subdir-makefiles)

jni/object/Android.mk,主要用來指定須要編譯出的動態庫的名稱,以及須要編譯的源文件,內容以下:spa

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE     := object_jni
LOCAL_SRC_FILES := object_jni.c

LOCAL_LDLIBS := -llog

include $(BUILD_SHARED_LIBRARY)

jni/object/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/object/object_jni.c,主要用來註冊綁定java函數和native函數,以及java函數在c中相應函數的具體實現, 內容以下:debug

#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"
#define JNIPAR_CLASS "com/clarck/jni/Person"

struct PersonOffsets
{
    jfieldID  name;
    jfieldID  age;
    jfieldID  height;
} gPersonOffsets;

typedef struct tagPerson
{
    char     mName[10];
    int        mAge;
    float    mHeight;
} Person;

static Person gPersons[] = {
        {"clarck", 25, 175},
        {"lilei", 30, 166},
        {"hanmeimei", 51, 172},
};

#define GPERSON_NUM NELEM(gPersons)

JNIEXPORT jint JNICALL native_object(JNIEnv *env, jobject clazz, jobject person, jint index) {
    if ((int) index < 0 || (int) index >= GPERSON_NUM)
        return -1;

    //將Person數組中的第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;
}

static void nativeClassInit(JNIEnv *env) {
    jclass personClass = (*env)->FindClass(env, JNIPAR_CLASS);
    gPersonOffsets.name     = (*env)->GetFieldID(env, personClass, "mName", "Ljava/lang/String;");
    gPersonOffsets.age      = (*env)->GetFieldID(env, personClass, "mAge", "I");
    gPersonOffsets.height     = (*env)->GetFieldID(env, personClass, "mHeight", "F");
}

/**
 * Java和JNI函數綁定
 */
static JNINativeMethod method_table[] = {
        { "getPersonInfoByIndex", "(Lcom/clarck/jni/Person;I)I", (void*) native_object },
};

/**
 * 註冊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) {
    nativeClassInit(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 {
    private Person mPerson = null;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        Log.d("Test", "onCreate");
        mPerson = new Person();
        for (int i = 0; i < 3; i++) {
            getPersonInfoByIndex(mPerson, i);
            Log.d("Test", "mPersion[" + i + "] -- " + mPerson);
        } 
    }
    
    private native int getPersonInfoByIndex(Person person, int index);
    
    static {
        System.loadLibrary("object_jni");
    }
    
}
package com.clarck.jni;

public class Person {
    private String mName;
    private int mAge;
    private float mHeight;
    
    @Override
    public String toString() {
        return "mName: " + mName + ", mAge: " + mAge + ", mHeight: " + mHeight;
    }
    
}

運行結果以下:

04-15 15:37:30.916: D/Test(31477): onCreate
04-15 15:37:30.916: D/jni_logger(31477): native_object index-0 mName:clarck, mAge:25, mHeight:175.000000
04-15 15:37:30.916: D/Test(31477): mPersion[0] -- mName: clarck, mAge: 25, mHeight: 175.0
04-15 15:37:30.916: D/jni_logger(31477): native_object index-1 mName:lilei, mAge:30, mHeight:166.000000
04-15 15:37:30.916: D/Test(31477): mPersion[1] -- mName: lilei, mAge: 30, mHeight: 166.0
04-15 15:37:30.916: D/jni_logger(31477): native_object index-2 mName:hanmeimei, mAge:51, mHeight:172.000000
04-15 15:37:30.916: D/Test(31477): mPersion[2] -- mName: hanmeimei, mAge: 51, mHeight: 172.0
相關文章
相關標籤/搜索