打通了链接Java世界和native世界的通道以后,摆在咱们面前的问题,就变为了,如何在native code中,来操做Java object呢?Java object能够分为以下3种: java
Java Language的基本数据类型,与C/C++中的那些基本数据类型并没有太大的差异,不管是做为参数传递,仍是要做为返回值。于是此处,对于Java Language的基本数据类型就再也不多作描述。下面主要说明一下在native code中访问Java Language中内置的引用数据类型和非Java Language内置的引用数据类型。 android
Java Language中内置的引用数据类型,又主要包括String和原始数据类型的数组。 数组
首先来看String。String所对应的native 类型为jstring。jstring既不一样于C风格的一‘\0’结尾的char *的string,也不一样于C++标准库中的string类型。咱们不能像操做C风格的string那样来操做jstring,而必须首先通过JNI函数的转换,转换为UTF-16编码的jchar array或者UTF-8编码的char array以后,再来作操做。JNI有专门提供一组函数来来完成这样的转换。这组函数以下: ide
能够看到这组函数大致上能够分为两个族,String*的那一族用于操做UTF-16的字串串,如将jstring转换为UTF-16编码的jchar 数组,获取jchar数组长度等;而StringUTF*的那一族,则用于操做UTF-8的字串。 函数
接下来,能够看一段code。首先,是在Java code中调用native 方法的部分: this
char[] text = new char[] { 0xE01, 0xE49, 0xE33, 0xE43, 0xE37, 0xE27, 0xE64 }; stringToJNI(String.valueOf(text, 0, text.length)); } public native String stringToJNI(String text);
而后是C/C++ code中对于native method的实现部分: 编码
static jstring HelloJni_stringToJNI( JNIEnv* env, jobject thiz, jstring text) { JniDebug("from HelloJni_stringToJNI"); const char* utf8Chars = env->GetStringUTFChars(text, NULL); jsize utf8Length = env->GetStringUTFLength(text); JniDebug("utf8Length = %d", utf8Length); if (utf8Chars == NULL) { return NULL; } JniDebug("String got from java world: %s", utf8Chars); env->ReleaseStringUTFChars(text, utf8Chars); const jchar* chars = env->GetStringChars(text, NULL); jsize unicodeLength = env->GetStringLength(text); JniDebug("unicodeLength = %d", unicodeLength); env->ReleaseStringChars(text, chars); return text; }
上面那段code的运行结果: spa
这个地方咱们看到,有用到GetStringChars和GetStringUTFChars及ReleaseStringChars和ReleaseStringUTFChars这几个函数,GetStringChars和GetStringUTFChars返回jstring通过转换的结果,对于这两个函数的第三个参数,若是isCopy不是NULL,则当作了copy时,*isCopy会被设置为JNI_TRUE,而没有作copy时,它被设置为JNI_FALSE。尤为值得咱们注意的是,每次调用GetString*函数以后,老是须要在适当的时候,来相应的调用ReleaseString*函数。不然,则会出现Leak,而产生一些莫名其妙的NE。另外,在Java code中,咱们看到String不是由ASCII范围内的字符,而是泰语字符的char[]转换而来。再来看native code中,传递给android log函数的参数,是java层的字串转换为UTF-8编码的结果。于是,咱们了解到一点,传递给android log函数参数,应该是一个UTF-8编码的字串。咱们知道,UTF-8不只能够兼容ASCII,还能够支持完整的Unicode字符。 指针
GetStringRegion和GetStringUTFRegion这两个函数,所作的事情,与GetStringChars和GetStringUTFChars所作的事情,并无很大的区别。最大的区别在于,前者会将jstring转换的结果copy进做为参数传递进去的buffer中。
code
GetStringCritical和ReleaseStringCritical这两个调用之间的code,则应被看成是处于一个临界区(“critical region”)。处于临界区的code,会有额外的一些限制。Inside a critical region, native code must not call other JNI functions, nor may the native code make any system call that may cause the current thread to block and wait for another thread in the virtual machine instance。固然,这两个函数的具体实现,则因Java VM的实现而异。
建立jstring的函数看起来也还清晰明确,不管是从UTF-8编码的char *建立,仍是从UTF-16编码的jchar *建立,JNI提供的接口都简单易用。
而后来看数组。对于基本数据类型的数组的访问,与对于String的访问,有不少类似的地方。咱们一样不能直接访问这些数组,而必需要通过JNI的转换。这种转换的接口也是分为3组,Get<Type>ArrayElements()这一组,会直接返回一个<NativeType>的指针,以后咱们就可使用C/C++中常规的访问数组的方法来访问基本数据类型的数组了。一样的,咱们同样须要在适当的地方调用相应的Release<Type>ArrayElements()函数以防止Leak;Get<Type>ArrayRegion()这一组,则能够将数组的成员copy进咱们传入的一个buffer中;而GetPrimitiveArrayCritical()则与前面的那个GetStringCritical()相似。咱们能够来看一下JNI提供的那些函数的原型,及简单的说明:
接下来咱们能够看一些code。首先,是Java code中对于native方法的调用的部分:
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); /* Create a TextView and set its content. * the text is retrieved by calling a native * function. */ TextView tv = new TextView(this); tv.setText(stringFromJNI()); setContentView(tv); int[] dataElement = new int[] { 2, 3, 4, 6 }; int sum = sumIntWithNative(dataElement, 0, dataElement.length); Log.d(TAG, "sum = " + sum); double[] doubleElement = new double[] { 3.4, 5.3, 7.6, 9.2 }; double doubleSum = sumDoubleWithNative(doubleElement, 0, doubleElement.length); Log.d(TAG, "doubleSum = " + doubleSum); char[] text = new char[] { 0xE01, 0xE49, 0xE33, 0xE43, 0xE37, 0xE27, 0xE64 }; stringToJNI(String.valueOf(text, 0, text.length)); } public native String stringToJNI(String text); public native int sumIntWithNative(int[] dataElement, int start, int end); public native double sumDoubleWithNative (double[] dataElement, int start, int end);
而后,是native code中对于native方法的实现的部分:
static jint HelloJni_sumIntWithNative( JNIEnv* env, jobject thiz, jintArray dataElement, jint start, jint end) { JniDebug("from HelloJni_sumIntWithNative"); jint sum = 0; jint*dateArray = env->GetIntArrayElements(dataElement, NULL); for (int i = start; i < end; ++ i) { sum += dateArray[i]; } env->ReleaseIntArrayElements(dataElement, dateArray, 0); return sum; } static jdouble HelloJni_sumDoubleWithNative( JNIEnv* env, jobject thiz, jdoubleArray dataElement, jint start, jint end) { JniDebug("from HelloJni_sumDoubleWithNative"); jdouble sum = 0.0; jdouble *dataArray = env->GetDoubleArrayElements(dataElement, NULL); for (int i = start; i < end; ++ i) { sum += dataArray[i]; } env->ReleaseDoubleArrayElements(dataElement, dataArray, 0); return sum; }
程序运行过程当中所打的log:
待续...