這篇文章主要講Java通過jni調用c層時如何傳遞參數,如何在c的代碼中回調Java的方法
上一篇 Android studio下jni的配置和第一個hello word程式
在上一個例子的基礎上繼續研究如何通過jni傳遞參數給c,其實傳遞參數很簡單,先說一下步驟:
1、在Java中定義native的含參的方法
2、使用javah產生標頭檔
3、在標頭檔中找到我們含參的方法,並在c中完善它的方法體,返回c最終的處理結果
下面一步一步來詳細說明:
public class JNIUtil { //直接從c擷取一個字串 public native String getStringFromC(); //傳遞int類型的參數給c,c返回處理結果 public native int addNum(int x, int y); //傳遞String類型的參數給C 處理一下返回來 public native String sayFromC(String s); //傳遞int類型的數組給C public native int[] arrElementsIncrease(int[] intArray);}
然後開啟Android studio 內建的Terminal,進入app/src/main 目錄下,使用如下命令:
javah -d jni -classpath D:\android_studio\sdk\platforms\android-23\android.jar;..\..\build\intermediates\classes\debug com.zhaocd.activity.myjnidemo1.JNIUtil
即可產生標頭檔com_zhaocd_activity_myjnidemo1_JNIUtil.h (注意:在JNIUtil中新增了方法後,必須先build -> rebuild preject 一下,不然class檔案還是以前的,產生的標頭檔中也沒有新增的方法)
開啟標頭檔,找到我們定義的native的幾個方法,然後將它們複製到hello.c的c檔案中,完善方法體:
/** * 返回兩個int類型變數的和 */JNIEXPORT jint JNICALL Java_com_zhaocd_activity_myjnidemo1_JNIUtil_addNum (JNIEnv * env, jobject obj, jint x, jint y){ return x+y;}
為了篇幅的長度,這裡只貼出一個方法,因為我們的重點不是c的編寫,需要源碼的可以在文章末尾下載。
可能大家也注意到了,int對應的jint,string對應的jstring ,其實這些基本的資料類型都是在jni.h這個檔案中定義好的
# include <inttypes.h> /* C99 */typedef uint8_t jboolean; /* unsigned 8 bits */typedef int8_t jbyte; /* signed 8 bits */typedef uint16_t jchar; /* unsigned 16 bits */typedef int16_t jshort; /* signed 16 bits */typedef int32_t jint; /* signed 32 bits */typedef int64_t jlong; /* signed 64 bits */typedef float jfloat; /* 32-bit IEEE 754 */typedef double jdouble; /* 64-bit IEEE 754 */#elsetypedef 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 */#endif/* "cardinal indices and sizes" */
一個整形,你定義成int,在產生標頭檔的時候jni自動會給你轉換成jint,知道這個的話就可以無視那個“j”了,ndk會把Java的資料類型和c的資料類型進行轉換。
除了基本的資料類型,肯定還有數組了
typedef void* jobject;typedef jobject jclass;typedef jobject jstring;typedef jobject jarray;typedef jarray jobjectArray;typedef jarray jbooleanArray;typedef jarray jbyteArray;typedef jarray jcharArray;typedef jarray jshortArray;typedef jarray jintArray;typedef jarray jlongArray;typedef jarray jfloatArray;typedef jarray jdoubleArray;typedef jobject jthrowable;typedef jobject jweak;
可以看到不管是什麼類型的數組,都是先轉換成jarray -> jobject -> void* 。 void*是一種特別的指標,說它特別是因為它不能判斷出資料的類型,或者說根據這個類型不能判斷出指向對象的長度。
由於我們開發項目時,一般很少自己去寫c層的代碼,而是使用一些開源的現成的類庫或者由c++工程師寫,所以這裡就不對c做深入的研究了~~~~
源碼下載