Android NDK开发系列教程:如何调用及传参方法
上一节主要讲解java向native传参,下面主要讲解从native传相应的数据到java层。
接着上一节,下面主要讲解内容如下:
1. native向java返回字符串类型
2. native向java返回java对象
3. native向java返回数组类型
4. native向java返回list对象
对于上面的每个都给出对应的例子。
本节所有案例代码均已放到github上,
1. native向java返回字符串类型
传基本数据类型很简单,是什么就传什么就行。传字符串类型也很简单,具体jni代码如下:
extern "c" jniexport jstring jnicall java_zqc_com_example_nativetest_jni2javamethod1(jnienv *env, jobject instance) { //jstring newstringutf(const char* bytes),jstring newstring(const jchar* unicodechars, jsize len) char *returnvalue = "你在native做你的操作后,生成char*后,通过env->newstringutf即可返回java的string类型"; return env->newstringutf(returnvalue); }
其中最主要用的是以下几个方法:
//创建unicode格式的jstring串 jstring newstring(const jchar* unicodechars, jsize len) { return functions->newstring(this, unicodechars, len); } //获取jstring长度 jsize getstringlength(jstring string) { return functions->getstringlength(this, string); } //获取jstring对应的字符串,iscopy表示是否拷贝生成副本。 //这个函数返回一个指向特定jstring中字符顺序的指针,该指针保持有效直到releasestringchars函数被调用: const jchar* getstringchars(jstring string, jboolean* iscopy) { return functions->getstringchars(this, string, iscopy); } //释放指针 void releasestringchars(jstring string, const jchar* chars) { functions->releasestringchars(this, string, chars); } ////创建utf-8格式的jstring串 jstring newstringutf(const char* bytes) { return functions->newstringutf(this, bytes); } //获取utf字符串的长度 jsize getstringutflength(jstring string) { return functions->getstringutflength(this, string); } //同getstringchars const char* getstringutfchars(jstring string, jboolean* iscopy) { return functions->getstringutfchars(this, string, iscopy); } //同releasestringchars void releasestringutfchars(jstring string, const char* utf) { functions->releasestringutfchars(this, string, utf); }
以上是处理字符串常用的一些方法。
2 native向java返回java对象
具体看native的代码如下:
extern "c" jniexport jobject jnicall java_zqc_com_example_nativetest_jni2javamethod2(jnienv *env, jobject instance) { jclass pcls = env->findclass("zqc/com/example/person"); jmethodid constructor = env->getmethodid(pcls, "", "()v"); jmethodid setidmid = env->getmethodid(pcls, "setid", "(j)v"); jmethodid setnamemid = env->getmethodid(pcls, "setname", "(ljava/lang/string;)v"); jmethodid setagemid = env->getmethodid(pcls, "setname", "(i)v"); jobject person = env->newobject(pcls, constructor); env->callvoidmethod(person, setidmid, 100l); env->callvoidmethod(person, setnamemid, env->newstringutf("天宇")); env->callvoidmethod(person, setagemid, 18); return person; }
常用新建object的方法由以下几个:
//将传递给构造函数的所有参数紧跟着放在 methodid 参数的后面。newobject() 收到这些参数后,将把它们传给所要调用的java 方法。 jobject newobject(jclass clazz, jmethodid methodid, ...) { va_list args; va_start(args, methodid); jobject result = functions->newobjectv(this, clazz, methodid, args); va_end(args); return result; } //将传递给构造函数的所有参数放在 va_list 类型的参数 args 中,该参数紧跟着放在 methodid 参数的后面。newobject() 收到这些参数后,将把它们传给所要调用的 java 方法。 jobject newobjectv(jclass clazz, jmethodid methodid, va_list args) { return functions->newobjectv(this, clazz, methodid, args); } //将传递给构造函数的所有参数放在jvalues类型的数组args中,该数组紧跟着放在methodid参数的后面。newobject() 收到数组中的这些参数后,将把它们传给所要调用的 java 方法。 jobject newobjecta(jclass clazz, jmethodid methodid, jvalue* args) { return functions->newobjecta(this, clazz, methodid, args); } //测试对象是否为某个类的实例。 jboolean isinstanceof(jobject obj, jclass clazz) { return functions->isinstanceof(this, obj, clazz); } //测试两个引用是否引用同一 java 对象。 jboolean issameobject(jobject ref1, jobject ref2) { return functions->issameobject(this, ref1, ref2); } //分配新 java 对象而不调用该对象的任何构造函数。返回该对象的引用。 //该方法会抛出:instantiationexception:如果该类为一个接口或抽象类。outofmemoryerror:如果系统内存不足。 jobject allocobject(jclass clazz) { return functions->allocobject(this, clazz); }
3 native向java返回数组类型
3.1 基本类型数组
这里直接看native层代码如下:
extern "c" jniexport jintarray jnicall java_zqc_com_example_nativetest_jni2javamethod3(jnienv *env, jobject instance) { int nat[] = {2, 1, 4, 3, 5}; jintarray jnat = env->newintarray(5); env->setintarrayregion(jnat, 0, 5, nat); return jnat; }
基本数据类型数组都有相应的env->newxxxarray(jsize length);通过该方法可以生成对应的数组。
jbooleanarray newbooleanarray(jsize length) { return functions->newbooleanarray(this, length); } jbytearray newbytearray(jsize length) { return functions->newbytearray(this, length); } jchararray newchararray(jsize length) { return functions->newchararray(this, length); } jshortarray newshortarray(jsize length) { return functions->newshortarray(this, length); } jintarray newintarray(jsize length) { return functions->newintarray(this, length); } jlongarray newlongarray(jsize length) { return functions->newlongarray(this, length); } jfloatarray newfloatarray(jsize length) { return functions->newfloatarray(this, length); } jdoublearray newdoublearray(jsize length) { return functions->newdoublearray(this, length); }
在生成了对应的数组后,可以通过setxxxarrayregion(jxxxarray array, jsize start, jsize len, const jchar* buf)来填充数组
void setbooleanarrayregion(jbooleanarray array, jsize start, jsize len, const jboolean* buf) { functions->setbooleanarrayregion(this, array, start, len, buf); } void setbytearrayregion(jbytearray array, jsize start, jsize len, const jbyte* buf) { functions->setbytearrayregion(this, array, start, len, buf); } void setchararrayregion(jchararray array, jsize start, jsize len, const jchar* buf) { functions->setchararrayregion(this, array, start, len, buf); } void setshortarrayregion(jshortarray array, jsize start, jsize len, const jshort* buf) { functions->setshortarrayregion(this, array, start, len, buf); } void setintarrayregion(jintarray array, jsize start, jsize len, const jint* buf) { functions->setintarrayregion(this, array, start, len, buf); } void setlongarrayregion(jlongarray array, jsize start, jsize len, const jlong* buf) { functions->setlongarrayregion(this, array, start, len, buf); } void setfloatarrayregion(jfloatarray array, jsize start, jsize len, const jfloat* buf) { functions->setfloatarrayregion(this, array, start, len, buf); } void setdoublearrayregion(jdoublearray array, jsize start, jsize len, const jdouble* buf) { functions->setdoublearrayregion(this, array, start, len, buf); }
3.2 对象类型数组
直接看native代码:
extern "c" jniexport jobjectarray jnicall java_zqc_com_example_nativetest_jni2javamethod4(jnienv *env, jobject instance) { jclass cls = env->findclass("zqc/com/example/person"); jmethodid cmid = env->getmethodid(cls, "", "()v"); jclass pcls = env->findclass("zqc/com/example/person"); jmethodid cmid = env->getmethodid(pcls, "", "()v"); jmethodid setnamemid = env->getmethodid(pcls, "setname", "(ljava/lang/string;)v"); jmethodid setagemid = env->getmethodid(pcls, "setage", "(i)v"); jobject obj = env->newobject(pcls, cmid); env->callvoidmethod(obj, setnamemid, env->newstringutf("天宇")); int len = 3; jobjectarray joa = env->newobjectarray(len, cls, obj); for (int i = 0; i < len; ++i) { jobject tmp = env->getobjectarrayelement(joa,i); env->callvoidmethod(tmp, setagemid, i + 10); } return joa; }
其在native生成的方法是 jobjectarray joa = env->newobjectarray(len, cls, obj);
//第一个参数表示生成的长度,第二参数表示里面元素的对象类,第三个表示原始初始化时的值。在生成后每个元素都是该值。 jobjectarray newobjectarray(jsize length, jclass elementclass, jobject initialelement) { return functions->newobjectarray(this, length, elementclass, initialelement); }
4 native向java返回list对象
直接看native代码如下:
extern "c" jniexport jobject jnicall java_zqc_com_example_nativetest_jni2javamethod5(jnienv *env, jobject instance) { jclass listcls = env->findclass("java/util/arraylist");//获得arraylist类引用 jmethodid listcon = env->getmethodid(listcls, "", "()v"); jmethodid addmid = env->getmethodid(listcls,"add","(ljava/lang/object;)z"); jobject listobj = env->newobject(listcls, listcon); jobject jperon = java_zqc_com_example_nativetest_jni2javamethod2(env, instance); env->callbooleanmethod(listobj, addmid, jperon); return listobj; }
对应jni而言,list,arraylist以及map,hashmap,set,hashset都只是一个object,对应于jni而言也就都是jobject,操作jobject都可以用最开始介绍的方法。
总结
jni里面的方法很多,多用用就熟悉了。常用的上面都有,自己之前还总结了很多常用的类型转换函数。
下一篇: 凉拌生芒果 你必须学会的一种芒果的吃法