Android NDK 學習之在C中調用Java的變量和靜態變量

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

在Eclipse中添加配置NDK,路徑如下Eclipse->Window->Preferences->Android->NDK ,選擇NDK的路徑,然後Apply即可。

新建一個名爲AndroidJNI_AccessField的Android工程,新建一個jni的文件夾,其目錄下文件樹列表如下:

├── jni
│   ├── accessfield
│   │   ├── accessfield_jni.c
│   │   ├── Android.mk
│   │   └── logger.h
│   ├── Android.mk
│   └── Application.mk

 

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

APP_ABI := all

jni/Android.mk,主要用來指定順序執行所有子文件夾下面的makefile文件,內容如下:

include $(call all-subdir-makefiles)

 

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

複製代碼
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE     := accessfield_jni
LOCAL_SRC_FILES := accessfield_jni.c

LOCAL_LDLIBS := -llog

include $(BUILD_SHARED_LIBRARY)
複製代碼

 

jni/accessfield/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/accessfield/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/AccessField"

/**
 * 返回成員實例域
 */
JNIEXPORT void JNICALL native_accessField(JNIEnv *env, jobject obj) {
    jfieldID fid;
    jstring jstr;
    const char *str;

    //在實力引用對象上得到類的引用
    jclass cls = (*env)->GetObjectClass(env, obj);
    //從類的引用,成員域的名稱,和成員域描述符來得到成員域(field)ID
    fid = (*env)->GetFieldID(env, cls, "mStr", "Ljava/lang/String;");
    if (NULL == fid) {
        return ;
    }

    //獲取傳遞對象引用和成員域ID獲取實例域訪問函數
    jstr = (*env)->GetObjectField(env, obj, fid);
    //獲取傳遞對象引用的字符
    str = (*env)->GetStringUTFChars(env, jstr, NULL);
    if (NULL == str) {
        return ;
    }
    LOGI("mStr = %s \n", str);
    (*env)->ReleaseStringUTFChars(env, jstr, str);

    jstr = (*env)->NewStringUTF(env, "123");
    if (NULL == jstr) {
        return ;
    }
    //替換掉獲取到的實例對象的引用
    (*env)->SetObjectField(env, obj, fid, jstr);

    //Caching at the Point of Use
    /*static jfieldID fid_s = NULL;
    jstring jstr;
    const char *str;

    jclass cls = (*env)->GetObjectClass(env, obj);
    if (NULL == fid_s) {
        fid_s = (*env)->GetFieldID(env, cls, "mStr", "Ljava/lang/String;");
        if (NULL == fid_s) {
            return ;
        }
    }
    LOGI("In C \n");

    jstr = (*env)->GetObjectField(env, obj, fid_s);
    str = (*env)->GetStringUTFChars(env, jstr, NULL);
    if (NULL == str) {
        return ;
    }
    LOGI("mStr = %s \n", str);
    (*env)->ReleaseStringUTFChars(env, jstr, str);
    jstr = (*env)->NewStringUTF(env, "123");
    if (NULL == jstr) {
        return ;
    }
    (*env)->SetObjectField(env, obj, fid_s, jstr);*/
}

/**
 * 得到靜態成員實例域
 */
JNIEXPORT void JNICALL native_staticAccessField(JNIEnv *env, jobject obj) {
    jfieldID fid;
    jint si;

    jclass cls = (*env)->GetObjectClass(env, obj);
    fid = (*env)->GetStaticFieldID(env, cls, "mSi", "I");
    if (NULL == fid) {
        return ;
    }

    si = (*env)->GetStaticIntField(env, cls, fid);
    LOGI("mSi = %d \n", si);
    (*env)->SetStaticIntField(env, cls, fid, 200);
}

/**
 * Java和JNI函數綁定
 */
static JNINativeMethod method_table[] = {
        { "accessField", "()V", (void*) native_accessField },
        { "staticAccessField", "()V", (void*) native_staticAccessField },
};

/**
 * 註冊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;

public class AccessField {
    public String mStr;
    public static int mSi;
    
    public native void accessField();
    public native void staticAccessField();

    static {
        System.loadLibrary("accessfield_jni");
    }
}
複製代碼
複製代碼
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);
        AccessField accessField = new AccessField();
        accessField.mStr = "abc";
        accessField.accessField();
        Log.d("Test", "mStr = " + accessField.mStr);
        
        accessField.mSi = 100;
        accessField.staticAccessField();
        Log.d("Test", "mStr = " + accessField.mSi);
    }

}
複製代碼

 

執行Ctrl+B執行編譯,運行工程即可。

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