Android JNI和NDK學習(08)--JNI實例一 傳遞基本類型數據


Android JNI和NDK學習(08)--JNI實例一 傳遞基本類型數據

 

本文介紹在Java和JNI之間相互傳遞基本數據類型的方法。

由於前面已經詳細介紹搭建和建立NDK工程的完整流程(參考“靜態實現流程”或“動態實現流程”),這里就不再介紹流程;而是將重點放在說明如何實現Java和JNI之間相互傳遞基本數據。

 

1 建立eclipse工程

建立工程NdkBasicParam,NdkBasicParam.java的內容如下:

package com.skywang.ndk;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
import android.util.Log;

public class NdkBasicParam extends Activity {
    private static final String TAG="sky--NdkBasicParam";
    
    private int ival;
    private float fval;
    private String str;
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        Log.d(TAG, "onCreate");
        
        // 獲取從jni傳來的整數
        ival = intFromJni();
        Log.d(TAG, "ival="+ival);
        
        // 將整數傳遞到jni
        intToJni((int)123); 
 
        // 獲取從jni傳來的float
        fval = floatFromJni();
        Log.d(TAG, "fval="+fval);
        
        // 將float傳遞到jni
        floatToJni((float)456.78);

        // 獲取從jni傳來的string
        str = stringFromJni(); 
        Log.d(TAG, "str="+str);
        
        // 將string傳遞到jni
        stringToJni("Hello From Java");
    }
    
    // jni中注冊的方法
    private native int intFromJni();
    private native void intToJni(int val);
    private native float floatFromJni();
    private native void floatToJni(float val);
    private native String stringFromJni();
    private native void stringToJni(String val);

    static {
        // 加載本地libndk_load.so庫文件
        System.loadLibrary("ndk_basic_param");
    }
}

NdkBasicParam.java的內容很簡單,主要就是調用一些JNI中注冊的本地方法。

 

2 實現JNI

(01) 在工程的jni目錄下新建ndk_basic_param.c

ndk_basic_param.c的代碼如下:

#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/NdkBasicParam"


// 引入log頭文件
#include <android/log.h>  

// log標簽
#define  TAG    "ndk_basic_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__)

/* 
 * 將字符串由JNI傳遞給Java
 * 參數說明:
 *         env : JNI 接口指針。
 *        claszz : Java 類對象。
 */
JNIEXPORT jstring JNICALL 
stringFromJni(JNIEnv *env, jobject clazz)
{
    // 將“Hello From jni”轉行成jstring類型
    jstring str = (*env)->NewStringUTF(env, "Hello From Jni");
    return str;
}


/* 
 * 將字符串從java從到jni層。
 * 參數說明:
 *         env : JNI 接口指針。
 *        claszz : Java 類對象。
 *        val : java傳遞給jni的string類型值。
 */
JNIEXPORT void JNICALL 
stringToJni(JNIEnv *env, jobject clazz, jstring val)
{
    // 將java傳遞給jni的string轉行成char *類型。
    // const char * GetStringUTFChars(JNIEnv *env, jstring string, jboolean *isCopy);
    // env:JNI 接口指針。
    // string:Java 字符串對象。
    // isCopy:指向布爾值的指針,JNI_TRUE或JNI_FALSE。
    //         JNI_TRUE  —— 開新內存,然后把java中的string拷貝到這個內存中,然后返回指向這個內存地址的指針。
    //         JNI_FALSE —— 直接返回指向java中String內存的指針,這個時候千萬不要改變這個內存的內容,這將破壞String在java中始終是常量這個原則。
    char *str = (char *)(*env)->GetStringUTFChars(env, val, JNI_FALSE);
    LOGD("%s str=%s\n", __func__, str);
}

/* 
 * 將“浮點數”由JNI傳遞給Java
 * 參數說明:
 *         env : JNI 接口指針。
 *        claszz : Java 類對象。
 */
JNIEXPORT jfloat JNICALL 
floatFromJni(JNIEnv *env, jobject clazz)
{
    return (jfloat)1.34;
}
/* 
 * 將“浮點數”從Java從到JNI層。
 * 參數說明:
 *         env : JNI 接口指針。
 *        claszz : Java 類對象。
 *        val : java傳遞給jni的浮點數。
 */
JNIEXPORT void JNICALL 
floatToJni(JNIEnv *env, jobject clazz, jfloat val)
{
    float f = (float)val;
    LOGD("%s f=%f\n", __func__, f);
}

/* 
 * 將“整數”由JNI傳遞給Java
 * 參數說明:
 *         env : JNI 接口指針。
 *        claszz : Java 類對象。
 */
JNIEXPORT jint JNICALL 
intFromJni(JNIEnv *env, jobject clazz)
{
    return (jint)25;
}
/* 
 * 將“整數”從Java從到JNI層。
 * 參數說明:
 *         env : JNI 接口指針。
 *        claszz : Java 類對象。
 *        val : java傳遞給jni的整數。
 */
JNIEXPORT void JNICALL 
intToJni(JNIEnv *env, jobject clazz, jint val)
{
    int i = (int)val;
    LOGD("%s i=%d\n", __func__, i);
}

// Java和JNI函數的綁定表
static JNINativeMethod method_table[] = {
    { "intFromJni"        , "()I"                    , (void*)intFromJni        },
    { "intToJni"        , "(I)V"                , (void*)intToJni        },
    { "floatFromJni"    , "()F"                    , (void*)floatFromJni    },
    { "floatToJni"        , "(F)V"                , (void*)floatToJni        },
    { "stringFromJni"    , "()Ljava/lang/String;"    , (void*)stringFromJni    },
    { "stringToJni"        , "(Ljava/lang/String;)V", (void*)stringToJni    },
};

// 注冊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_basic_ndk_param(JNIEnv *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_basic_ndk_param(env);

    // 返回jni的版本
    return JNI_VERSION_1_4;
}

JNI_OnLoad()會在JNI注冊時被回調。 JNI_OnLoad()調用register_basic_ndk_param(),而register_basic_ndk_param()調用registerNativeMethods();在registerNativeMethods()中將method_table注冊到Java中。然后就可以通過Java調用注冊的函數。

 

(02) 實現Android.mk

在工程的jni目錄下新建Android.mk,Android.mk的代碼如下:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := ndk_basic_param
LOCAL_SRC_FILES := ndk_basic_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 運行工程

打印信息如下:

D/sky--NdkBasicParam: onCreate
D/sky--NdkBasicParam: ival=25
D/ndk_basic_param: intToJni i=123
D/sky--NdkBasicParam: fval=1.34
D/ndk_basic_param: floatToJni f=456.779999
D/sky--NdkBasicParam: str=Hello From Jni
D/ndk_basic_param: stringToJni str=Hello From Java

  

點擊下載:"源代碼"

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM