[Android的系统移植与平台开发]JNI介绍(5)

2014-06-06
浏览
导读:3.5 本地创建Java对象 1)本地代码创建Java对象 JNIEnv提供了下面几个方法来创建一个Java对象: jobject NewObject(jclass clazz, jmethodID methodID,...); jobject NewObjectV(jclass clazz, jmethodIDmethodID,va

3.5 本地创建Java对象

1)        本地代码创建Java对象

JNIEnv提供了下面几个方法来创建一个Java对象:

jobject NewObject(jclass clazz, jmethodID methodID,...);

jobject NewObjectV(jclass clazz, jmethodIDmethodID,va_list args);

jobject NewObjectA(jclass clazz, jmethodID methodID,const jvalue *args) ;

本地创建Java对象的函数和前面本地调用Java方法很类似:

第一个参数jclass class  代表的你要创建哪个类的对象

第二个参数jmethodID methodID 代表你要使用哪个构造方法ID来创建这个对象。

只要有jclass和jmethodID ,我们就可以在本地方法创建这个Java类的对象。

指的一提的是:由于Java的构造方法的特点,方法名与类名一样,并且没有返回值,所以对于获得构造方法的ID的方法env->GetMethodID(clazz,method_name ,sig)中的第二个参数是固定为类名,第三个参数和要调用的构造方法有关,默认的Java构造方法没有返回值,没有参数。例如:

jclassclazz=env->FindClass("java/util/Date");                                     //取得java.util.Date类的jclass对象

jmethodID id_date=env->GetMethodID(clazz,"Date","()V");    //取得某一个构造方法的jmethodID

jobject date=env->NewObject(clazz,id_date);                             //调用NewObject方法创建java.util.Date对象

2)        本地方法对Java字符串的操作

在Java中,字符串String对象是Unicoode(UTF-16)编码,每个字符不论是中文还是英文还是符号,一个字符总是占用两个字节。在C/C++中一个字符是一个字节, C/C++中的宽字符是两个字节的。所以Java通过JNI接口可以将Java的字符串转换到C/C++的宽字符串(wchar_t*),或是传回一个UTF-8的字符串(char*)到C/C++,反过来,C/C++可以通过一个宽字符串,或是一个UTF-8编码的字符串创建一个Java端的String对象。

可以看下面的一个例子:

在Java端有一个字符串 String str="abcde";,在本地方法中取得它并且输出:

void native_string_operation (JNIEnv * env,  jobject obj)

{

         //取得该字符串的jfieldID

jfieldIDid_string=env->GetFieldID(env->GetObjectClass(obj), "str", "Ljava/lang/String;");

         jstringstring=(jstring)(env->GetObjectField(obj, id_string));    //取得该字符串,强转为jstring类型。

    printf("%s",string);

}

由上面的代码可知,从java端取得的String属性或者是方法返回值的String对象,对应在JNI中都是jstring类型,它并不是C/C++中的字符串。所以,我们需要对取得的 jstring类型的字符串进行一系列的转换,才能使用。

JNIEnv提供了一系列的方法来操作字符串:

l  const jchar *GetStringChars(jstring str, jboolean*isCopy) 

将一个jstring对象,转换为(UTF-16)编码的宽字符串(jchar*)。

l  const char *GetStringUTFChars(jstring str,jboolean *isCopy)

将一个jstring对象,转换为(UTF-8)编码的字符串(char*)。

这两个函数的参数中,第一个参数传入一个指向Java 中String对象的jstring引用。第二个参数传入的是一个jboolean的指针,其值可以为NULL、JNI_TRUE、JNI_FLASE。

如果为JNI_TRUE则表示开辟内存,然后把Java中的String拷贝到这个内存中,然后返回指向这个内存地址的指针。

如果为JNI_FALSE,则直接返回指向Java中String的内存指针。这时不要改变这个内存中的内容,这将破坏String在Java中始终是常量的规则。

如果是NULL,则表示不关心是否拷贝字符串。

 

使用这两个函数取得的字符,在不适用的时候,要分别对应的使用下面两个函数来释放内存。

RealeaseStringChars(jstring jstr, const jchar*str)

RealeaseStringUTFChars(jstring jstr, constchar* str)

第一个参数指定一个jstring变量,即要释放的本地字符串的资源

第二个参数就是要释放的本地字符串

3)        创建Java String对象

jstring NewString(const jchar *unicode, jsizelen)            // 根据传入的宽字符串创建一个Java String对象

jstring NewStringUTF(const char *utf)                    // 根据传入的UTF-8字符串创建一个Java String对象

4)        返回Java String对象的字符串长度

jsize GetStringLength(jstring jstr)                   //返回一个java String对象的字符串长度

jsize GetStringUTFLength(jstring jstr)             //返回一个java String对象经过UTF-8编码后的字符串长度

3.6 Java数组在本地代码中的处理

我们可以使用GetFieldID获取一个Java数组变量的ID,然后用GetObjectFiled取得该数组变量到本地方法,返回值为jobject,然后我们可以强制转换为j<Type>Array类型。

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 jarray jobjectArray;

j<Type>Array类型是JNI定义的一个对象类型,它并不是C/C++的数组,如int[]数组,double[]数组等等。所以我们要把j<Type>Array类型转换为C/C++中的数组来操作。

JNIEnv定义了一系列的方法来把一个j<Type>Array类型转换为C/C++数组或把C/C++数组转换为j<Type>Array。

jsize GetArrayLength(jarray array)                                                        // 获得数组的长度

jobjectArray NewObjectArray(jsize len, jclass clazz, jobjectinit)                  // 创建对象数组,指定其大小

jobject GetObjectArrayElement(jobjectArray array, jsizeindex)                   // 获得数组的指定元素

void SetObjectArrayElement(jobjectArray array, jsizeindex,jobject val)      // 设置数组元素

 

 jbooleanArrayNewBooleanArray(jsize len)            // 创建Boolean数组,指定其大小

 jbyteArrayNewByteArray(jsize len)                        //下面的都类似,创建对应类型的数组,并指定大小

 jcharArrayNewCharArray(jsize len)

 jshortArrayNewShortArray(jsize len)

 jintArrayNewIntArray(jsize len)

 jlongArrayNewLongArray(jsize len)

 jfloatArrayNewFloatArray(jsize len)

 jdoubleArrayNewDoubleArray(jsize len)

// 获得指定类型数组的元素

jboolean * GetBooleanArrayElements(jbooleanArray array,jboolean *isCopy)

jbyte * GetByteArrayElements(jbyteArray array, jboolean*isCopy)

jchar * GetCharArrayElements(jcharArray array, jboolean*isCopy)

jshort * GetShortArrayElements(jshortArray array, jboolean*isCopy)

jint * GetIntArrayElements(jintArray array, jboolean*isCopy)

jlong * GetLongArrayElements(jlongArray array, jboolean*isCopy)

jfloat * GetFloatArrayElements(jfloatArray array,jboolean *isCopy)

jdouble * GetDoubleArrayElements(jdoubleArray array,jboolean *isCopy)

// 释放指定数组

void ReleaseBooleanArrayElements(jbooleanArrayarray,jboolean *elems,jint mode)

void ReleaseByteArrayElements(jbyteArray array,jbyte*elems,jint mode)

void ReleaseCharArrayElements(jcharArray array,jchar*elems,jint mode)

void ReleaseShortArrayElements(jshortArray array,jshort*elems,jint mode)

void ReleaseIntArrayElements(jintArray array,jint*elems,jint mode)

void ReleaseLongArrayElements(jlongArray array,jlong*elems,jint mode)

void ReleaseFloatArrayElements(jfloatArray array,jfloat*elems,jint mode)

void ReleaseDoubleArrayElements(jdoubleArrayarray,jdouble *elems,jint mode)

 

void * GetPrimitiveArrayCritical(jarray array, jboolean*isCopy)

void ReleasePrimitiveArrayCritical(jarray array, void*carray, jint mode)

 

void GetBooleanArrayRegion(jbooleanArray array,jsizestart, jsize len, jboolean *buf)

void GetByteArrayRegion(jbyteArray array,jsize start,jsize len, jbyte *buf)

void GetCharArrayRegion(jcharArray array,jsize start,jsize len, jchar *buf)

void GetShortArrayRegion(jshortArray array,jsize start,jsize len, jshort *buf)

void GetIntArrayRegion(jintArray array,jsize start,jsize len, jint *buf)

void GetLongArrayRegion(jlongArray array,jsize start,jsize len, jlong *buf)

void GetFloatArrayRegion(jfloatArray array,jsize start,jsize len, jfloat *buf)

void GetDoubleArrayRegion(jdoubleArray array,jsizestart, jsize len, jdouble *buf)

void SetBooleanArrayRegion(jbooleanArray array, jsizestart, jsize len,const jboolean *buf)

void SetByteArrayRegion(jbyteArray array, jsize start,jsize len,const jbyte *buf)

void SetCharArrayRegion(jcharArray array, jsize start,jsize len,const jchar *buf)

void SetShortArrayRegion(jshortArray array, jsizestart, jsize len,const jshort *buf)

void SetIntArrayRegion(jintArray array, jsize start,jsize len,const jint *buf)

void SetLongArrayRegion(jlongArray array, jsize start,jsize len,const jlong *buf)

void SetFloatArrayRegion(jfloatArray array, jsizestart, jsize len,const jfloat *buf)

void SetDoubleArrayRegion(jdoubleArray array, jsizestart, jsize len,const jdouble *buf)

编程实现Android远程控制PC

[Android的系统移植与平台开发]Sensor HAL

[Android的系统移植与平台开发]Sensor HAL

用ViewPager实现高仿图片左右滑动自动切换

详解android Content Provider[6]