學習一門新的程式設計語言,資料類型是最基本的東西,這裡我們講述下jni中的資料類型。
在JNI中把資料類型分為3類:
primitive type:int float char
reference type:class instances arrays
string type
在 HelloWorld中我們列印出HelloWorld等字樣,我們沒有傳入任何參數,這裡先給出一個例子,我們在java端傳入字串,然後看在jni中時如何做處理的。
這個例子跟之前的Helloworld差不多,稍作修改,我們在java端傳入參數,
建立一個類,專門用來封轉jni的method:
[java]
package com.android.jni;
public class Prompt {
public native String getLine(String prompt);
static {
System.loadLibrary("MyJNI");
}
}
在主activity中調用:
[java]
//調用原生函數得到字串str
Prompt pmt = new Prompt();
String str=pmt.getLine("Put in a line!");
//吐出message
Toast.makeText(mContext, str, Toast.LENGTH_SHORT).show();
我們調用了Prompt中的getLine方法。
然後看下C中的代碼:
[cpp]
jstring
Java_com_android_jni_Prompt_getLine(JNIEnv* env,jobject jobj,jstring prompt)
{
char buf[128];
const jbyte *str;
str = (*env)->GetStringUTFChars(env,prompt,NULL);
if(str == NULL)
return NULL;
__android_log_print(ANDROID_LOG_INFO,"-JNI-","%s",str);
(*env)->ReleaseStringUTFChars(env,prompt,str);
sprintf(buf,"From C + %s",str);
return (*env)->NewStringUTF(env,buf);
}
getLine函數呼叫了JNI的功能函數GetStringUFTChars來讀取我們傳入的prompt字串(java端)。GetStringUFTChars函數進入JNIEnv 結構指標,把java中的UTF-8字元類型轉變成C中的Unicode sequence,轉換成jstring 參考來使用。
最後在釋放str的時候不要忘記檢查str是否為空白,因為GetStringUFTChars函數可能會調用失敗(outofmenory)。
當原生代碼把傳進來的UTF-8類型字串之後應該立即釋放記憶體調用ReleaseStringUTFChars。
調用NewStringUTF函數來構建新的字串return給java代碼。
在模擬器中運行,當我們點擊按鈕的時候會出現字串,“From C + 。。。”
調用成功。
---------------------------------------------------------------------------------
下面我們來進入數組,先看下面的數組定義:
int[] iarr;
float[] farr;
Object oarr;
int[][] arr2;
iarr和farr是資料數組,但是oarr和arr2是對象數組。
下面舉個例子進入資料數組:
先看下我們要實現的,在java代碼中:
[cpp]
//調用原生函數得到字串str
//Prompt pmt = new Prompt();
//String str=pmt.getLine("Put in a line!");
int arr[] = new int[10];
for(int i=0;i<10;i++)
arr[i]=i;
int sum = IntArray.sumArray(arr);
//吐出message
Toast.makeText(mContext, "sum = "+sum, Toast.LENGTH_SHORT).show();
封裝動態庫function:
[cpp]
package com.android.jni;
public class IntArray {
public native static int sumArray(int[] arr);
static {
System.loadLibrary("IntArray");
}
}
定義一個數組,然後調用jni中的function來對數組進行操作,這邊在java代碼中傳進去的是一個整形的數組。
-----------------------------------------------------------------------------------------------
我們來看下在jni中是如何處理的:
[cpp]
jint
Java_com_android_jni_Native_sumArray(JNIEnv* env,jobject jobj,jintArray arr)
{
jint buf[10];
jint i, sum = 0;
(*env)->GetIntArrayRegion(env,arr,0,10,buf);
for(i=0;i<10;i++)
sum += buf[i];
return sum;
}
這裡調用了GetIntArrayRegion函數來把傳進來的arr數組中的資料都拷貝進C,該函數第三個參數是索引的開始值,第四個參數是被拷貝的數。
JNI也可以使用Get/Release<Type>ArrayElements 函數來使原生代碼直接擁有數組的指標。
[cpp]
Java_com_android_jni_Native_sumArray(JNIEnv* env,jobject jobj,jintArray arr)
{
// jint buf[10];
jint *carr;
jint i, sum = 0;
// (*env)->GetIntArrayRegion(env,arr,0,10,buf);
carr = (*env)->GetIntArrayElements(env,arr,NULL);
if(carr == NULL)
return 0;
for(i=0;i<10;i++)
sum += carr[i];
(*env)->ReleaseIntArrayElements(env,arr,carr,0);
return sum;
}
運行模擬器:
----------------------------------------------------------------------------------------
下面我們來看下jni中對對象數組的處理。
看下原生函數的聲明
[cpp]
public static native int[][] intitInt2DArray(int size);
下面是jni中的實現
[cpp] v
jobjectArray
Java_com_android_jni_Native_initInt2DArray(JNIEnv *env,
jclass cls,int size)
{
jobjectArray result;
int i;
jclass intArrCls = (*env)->FindClass(env, "[I");
if (intArrCls == NULL) {
return NULL; /* exception thrown */
}
result = (*env)->NewObjectArray(env, size, intArrCls,NULL);
if (result == NULL) {
return NULL; /* out of memory error thrown */
}
for (i = 0; i < size; i++) {
jint tmp[256]; /* make sure it is large enough! */
int j;
jintArray iarr = (*env)->NewIntArray(env, size);
if (iarr == NULL) {
return NULL; /* out of memory error thrown */
}
for (j = 0; j < size; j++) {
tmp[j] = i + j;
}
(*env)->SetIntArrayRegion(env, iarr, 0, size, tmp);
(*env)->SetObjectArrayElement(env, result, i, iarr);
(*env)->DeleteLocalRef(env, iarr);
}
return result;
}
------------------------------------------------------------------------------------------
ok,我們的基礎資料型別 (Elementary Data Type)就介紹到這,這裡資料類型還有很多,大家可以參考user guide,一般我遇到新類型就去翻資料。
下面我們會介紹jni是如何調用java中的成員函數和成員變數的。