android jni——basic Types, Strings and Arrays

来源:互联网 发布:php 根目录表示方法 编辑:程序博客网 时间:2024/06/05 05:41

学习一门新的编程语言,数据类型是最基本的东西,这里我们讲述下jni中的数据类型。

在JNI中把数据类型分为3类:

primitive type:int float char

reference type:class instances arrays

string type

在上一篇HelloWorld中我们打印出HelloWorld等字样,我们没有传入任何参数,这里先给出一个例子,我们在java端传入字符串,然后看在jni中时如何做处理的。

这个例子跟之前的Helloworld差不多,稍作修改,我们在java端传入参数,

新建一个类,专门用来封转jni的method:

[java] view plaincopy
  1. package com.android.jni;  
  2.   
  3. public class Prompt {  
  4.     public native String getLine(String prompt);  
  5.     static {  
  6.         System.loadLibrary("MyJNI");  
  7.     }  
  8.   
  9. }  

在主activity中调用:

[java] view plaincopy
  1. //调用原生函数得到字符串str  
  2. Prompt pmt = new Prompt();  
  3. String str=pmt.getLine("Put in a line!");  
  4. //吐出message  
  5. Toast.makeText(mContext, str, Toast.LENGTH_SHORT).show();  
  6.           

我们调用了Prompt中的getLine方法。

然后看下C中的代码:

[cpp] view plaincopy
  1. jstring  
  2. Java_com_android_jni_Prompt_getLine(JNIEnv* env,jobject jobj,jstring prompt)  
  3. {  
  4.     char buf[128];  
  5.     const jbyte *str;  
  6.     str = (*env)->GetStringUTFChars(env,prompt,NULL);  
  7.     if(str == NULL)  
  8.         return NULL;  
  9.     __android_log_print(ANDROID_LOG_INFO,"-JNI-","%s",str);  
  10.     (*env)->ReleaseStringUTFChars(env,prompt,str);  
  11.     sprintf(buf,"From C + %s",str);  
  12.     return (*env)->NewStringUTF(env,buf);  
  13. }  

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] view plaincopy
  1. //调用原生函数得到字符串str  
  2. //Prompt pmt = new Prompt();  
  3. //String str=pmt.getLine("Put in a line!");  
  4. int arr[] = new int[10];  
  5. for(int i=0;i<10;i++)  
  6.     arr[i]=i;  
  7. int sum = IntArray.sumArray(arr);  
  8. //吐出message  
  9. Toast.makeText(mContext, "sum = "+sum, Toast.LENGTH_SHORT).show();  

封装动态库function:


[cpp] view plaincopy
  1. package com.android.jni;  
  2.   
  3. public class IntArray {  
  4.     public native static int sumArray(int[] arr);  
  5.   
  6.     static {  
  7.         System.loadLibrary("IntArray");  
  8.     }  
  9. }  


定义一个数组,然后调用jni中的function来对数组进行操作,这边在java代码中传进去的是一个整形的数组。

-----------------------------------------------------------------------------------------------

我们来看下在jni中是如何处理的:

[cpp] view plaincopy
  1. jint  
  2. Java_com_android_jni_Native_sumArray(JNIEnv* env,jobject jobj,jintArray arr)  
  3. {  
  4.     jint buf[10];  
  5.     jint i, sum = 0;  
  6.     (*env)->GetIntArrayRegion(env,arr,0,10,buf);  
  7.     for(i=0;i<10;i++)  
  8.         sum += buf[i];  
  9.     return sum;  
  10. }  


这里调用了GetIntArrayRegion函数来把传进来的arr数组中的数据都拷贝进C,该函数第三个参数是索引的开始值,第四个参数是被拷贝的数。

JNI也可以使用Get/Release<Type>ArrayElements 函数来使原生代码直接拥有数组的指针。

[cpp] view plaincopy
  1. jint  
  2. Java_com_android_jni_Native_sumArray(JNIEnv* env,jobject jobj,jintArray arr)  
  3. {  
  4. //  jint buf[10];  
  5.     jint *carr;  
  6.     jint i, sum = 0;  
  7. //  (*env)->GetIntArrayRegion(env,arr,0,10,buf);  
  8.     carr = (*env)->GetIntArrayElements(env,arr,NULL);  
  9.     if(carr == NULL)  
  10.         return 0;  
  11.     for(i=0;i<10;i++)  
  12.         sum += carr[i];  
  13.     (*env)->ReleaseIntArrayElements(env,arr,carr,0);  
  14.     return sum;  
  15. }  

运行模拟器:


----------------------------------------------------------------------------------------

下面我们来看下jni中对对象数组的处理。

看下原生函数的声明

[cpp] view plaincopy
  1. public static native int[][] intitInt2DArray(int size);   

下面是jni中的实现

[cpp] view plaincopy
  1. jobjectArray  
  2. Java_com_android_jni_Native_initInt2DArray(JNIEnv *env,  
  3.         jclass cls,int size)  
  4. {  
  5.     jobjectArray result;  
  6.     int i;  
  7.     jclass intArrCls = (*env)->FindClass(env, "[I");  
  8.     if (intArrCls == NULL) {  
  9.         return NULL; /* exception thrown */  
  10.     }  
  11.     result = (*env)->NewObjectArray(env, size, intArrCls,NULL);  
  12.     if (result == NULL) {  
  13.         return NULL; /* out of memory error thrown */  
  14.     }  
  15.     for (i = 0; i < size; i++) {  
  16.         jint tmp[256]; /* make sure it is large enough! */  
  17.         int j;  
  18.         jintArray iarr = (*env)->NewIntArray(env, size);  
  19.         if (iarr == NULL) {  
  20.             return NULL; /* out of memory error thrown */  
  21.         }  
  22.         for (j = 0; j < size; j++) {  
  23.             tmp[j] = i + j;  
  24.         }  
  25.         (*env)->SetIntArrayRegion(env, iarr, 0, size, tmp);  
  26.         (*env)->SetObjectArrayElement(env, result, i, iarr);  
  27.         (*env)->DeleteLocalRef(env, iarr);  
  28.     }  
  29.     return result;  
  30. }  

------------------------------------------------------------------------------------------

ok,我们的基本数据类型就介绍到这,这里数据类型还有很多,大家可以参考user guide,一般我遇到新类型就去翻资料。

下面我们会介绍jni是如何调用java中的成员函数和成员变量的。


原创粉丝点击