編輯:關於Android編程
前幾篇學習了jni開發的基本流程、動態注冊native函數以及相關編譯文件的編寫,咱們也算是知道了jni開發,但是還不夠,今天咱們來學習下,java和jni的數據類型映射(說白了就是對應關系),以及如何在jni層調用java層的一些東西。偷偷告訴你們,這些全在jni.h文件裡。
首先是我們的基本數據類型,其關系如下表描述這樣。
上面關系的相關代碼在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 {};
我們這裡的調用包括許多方面,如:
調用靜態方法 調用實例方法 獲取字段值 修改字段值 構造對象 等等而要實現上面的一些功能,同樣要依靠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); }
很簡單,我們可以通過FindClass方法去查找類。
jclass clazz = env->FindClass("com/example/cmake_demo/MainActivity");
大致為以下四種方法
env->GetxxxField() env->GetStaticxxxField() env->GetMethodID() env->GetxxxMethodID()
上面沒有列出參數,但是仍然很明白,這裡就不多說了。
這裡呢。大致分為以下四種:
env->CallXXXMethod(); env->CallxxxMethodA(); env->CallxxxMethodV(); env->CallNonvirtualBooleanMethod()
同樣,我這裡沒給出方法的參數,同學們自己看jni.h吧
調用方法(這裡的方法可能使靜態的、也可能是非靜態的) 和上面的區別就在於對應的java層參數,在這裡以數組的形式傳進入 和1的區別就是,以v(矢量?)的形式傳進去,這裡我也不是很理解,希望知道的同學指點下。 調用構造函數初始化一個對象,這個,馬上說道。相信到這裡,大家猜都能猜出來,set 麼,這裡我就不叨叨了。
有些情況下我們是需要構造出java層的對象的,那麼如何構造呢,我們有兩種辦法。
NewObject方法 CallNonvirtualxxMethod先說第一種,NewObject方法,除了要求jclass參數之外,還要求jmethodid,以及java稱構造方法對應的參數。其他兩個還好,關鍵是這個jmethodID,這個在獲取的時候,方法名固定是< init >(md語法的原因,注意尖括號之間沒有空格),別問為什麼。
在來說說第二種,第二中使用時這樣的
jobject jo = env->AllocObject(clazz); env->CallNonvirtualVoidMethod(jo,clazz,jmethodId,arg )第一行代碼 創建未初始化的對象,並分配內存 第二行代碼,調用init那個方法(構造方法)進行初始化,注意,只能初始化一次。
現在我們明白了jni 和 java的數據類型映射關系,以及在jni層調用java層的方法。
效果圖 概述:ItemTouchHelperAdapter:(★)RecyclerListAdapter需要實現這個接口,RecyclerListAdapter
ButterKnife是一個專注於Android系統的View注入框架,可以減少大量的findViewById以及 setOnClickListener代碼,可視化一鍵生
APP的開發中,會常遇到這樣的需求:批量取消(刪除)List中的數據。這就要求ListVIew支持批量選擇、全選、單選等等功能,做一個比較強大的ListView批量選擇功
碎片之間進行交互 點擊下載源碼 很多時候,一個活動中包含一個或者多個碎片,它們彼此協作,向用戶展示一個一致的UI。在這種情況下,碎片之間能進行通信並交換數據十