Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android JNI學習筆記(四)-數據類型映射以及native調用java

Android JNI學習筆記(四)-數據類型映射以及native調用java

編輯:關於Android編程

1. 前言

前幾篇學習了jni開發的基本流程、動態注冊native函數以及相關編譯文件的編寫,咱們也算是知道了jni開發,但是還不夠,今天咱們來學習下,java和jni的數據類型映射(說白了就是對應關系),以及如何在jni層調用java層的一些東西。偷偷告訴你們,這些全在jni.h文件裡。

2. 數據類型映射

首先是我們的基本數據類型,其關系如下表描述這樣。

這裡寫圖片描述

上面關系的相關代碼在jni.h的44-51行,如下

typedef unsigned char   jboolean;       /* unsigned 8 bits */
typedef signed char     jbyte;          /* signed 8 bits */
typedef unsigned short  jchar;          /* unsigned 16 bits */
typedef short           jshort;         /* signed 16 bits */
typedef int             jint;           /* signed 32 bits */
typedef long long       jlong;          /* signed 64 bits */
typedef float           jfloat;         /* 32-bit IEEE 754 */
typedef double          jdouble;        /* 64-bit IEEE 754 */

而jni層的引用類型則是下面這個樣子。

這裡寫圖片描述

對於這些引用類型,c++和c的實現是不一樣的。如果是c++的話,所有引用類型派生自 jobject,如果使用 C 語言編寫的話,所有引用類型使用 jobject,其它引用類型使用 typedef 重新定義。同樣代碼也在jni.h中。這裡只給出c++繼承結構的部分。

class _jobject {};
class _jclass : public _jobject {};
class _jstring : public _jobject {};
class _jarray : public _jobject {};
class _jobjectArray : public _jarray {};
class _jbooleanArray : public _jarray {};
class _jbyteArray : public _jarray {};
class _jcharArray : public _jarray {};
class _jshortArray : public _jarray {};
class _jintArray : public _jarray {};
class _jlongArray : public _jarray {};
class _jfloatArray : public _jarray {};
class _jdoubleArray : public _jarray {};
class _jthrowable : public _jobject {};

3. native 如何調用c

我們這裡的調用包括許多方面,如:

調用靜態方法 調用實例方法 獲取字段值 修改字段值 構造對象 等等

而要實現上面的一些功能,同樣要依靠jni.h的JNINativeInterface這個結構體,這裡有很多很多的方法,供我們使用來實現native 調用java層的功能。而調用的流程是這樣的:

根據全限定名在jvm中找到想要的類 從jclass中獲取到method、或者field 執行獲取值、修改值、調用方法或者其他的操作 釋放局部引用

舉個調用靜態方法的例子看看。

void callJavaStatic(JNIEnv *env,jobject jobj){
  char* str = "call from c++";

  jclass clazz = env->FindClass("com/example/cmake_demo/MainActivity");
  if (clazz == NULL) {
    LOGE("class is null");
    return;
  }

  jmethodID method = env->GetStaticMethodID(clazz,"javaStaticMethod","(Ljava/lang/String;)V");
  if (method == NULL) {
    LOGE("not find method");
  }

  jstring  jstr = env->NewStringUTF(str);
  env->CallStaticVoidMethod(clazz,method,jstr);
  env->DeleteLocalRef(clazz);
  env->DeleteLocalRef(jstr);
}

3.1 如何找到類

很簡單,我們可以通過FindClass方法去查找類。

jclass clazz = env->FindClass("com/example/cmake_demo/MainActivity");

3.2 如何獲取方法、或者字段

大致為以下四種方法

 env->GetxxxField()
 env->GetStaticxxxField()
 env->GetMethodID()
 env->GetxxxMethodID()

上面沒有列出參數,但是仍然很明白,這裡就不多說了。

3.3 如何調用方法

這裡呢。大致分為以下四種:

  env->CallXXXMethod();
  env->CallxxxMethodA();
  env->CallxxxMethodV();
  env->CallNonvirtualBooleanMethod()

同樣,我這裡沒給出方法的參數,同學們自己看jni.h吧

調用方法(這裡的方法可能使靜態的、也可能是非靜態的) 和上面的區別就在於對應的java層參數,在這裡以數組的形式傳進入 和1的區別就是,以v(矢量?)的形式傳進去,這裡我也不是很理解,希望知道的同學指點下。 調用構造函數初始化一個對象,這個,馬上說道。

3.4 如何修改字段的值

相信到這裡,大家猜都能猜出來,set 麼,這裡我就不叨叨了。

3.5 如何構造一個對象出來

有些情況下我們是需要構造出java層的對象的,那麼如何構造呢,我們有兩種辦法。

NewObject方法 CallNonvirtualxxMethod

先說第一種,NewObject方法,除了要求jclass參數之外,還要求jmethodid,以及java稱構造方法對應的參數。其他兩個還好,關鍵是這個jmethodID,這個在獲取的時候,方法名固定是< init >(md語法的原因,注意尖括號之間沒有空格),別問為什麼。

在來說說第二種,第二中使用時這樣的

  jobject  jo = env->AllocObject(clazz);
  env->CallNonvirtualVoidMethod(jo,clazz,jmethodId,arg )
第一行代碼 創建未初始化的對象,並分配內存 第二行代碼,調用init那個方法(構造方法)進行初始化,注意,只能初始化一次。

4. 總結

現在我們明白了jni 和 java的數據類型映射關系,以及在jni層調用java層的方法。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved