欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android NDK开发系列教程:如何调用及传参方法

程序员文章站 2022-06-03 19:06:15
上一节主要讲解java向native传参,下面主要讲解从native传相应的数据到java层。 接着上一节,下面主要讲解内容如下: 1. native向java返回字符串类型 2. native向j...

上一节主要讲解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里面的方法很多,多用用就熟悉了。常用的上面都有,自己之前还总结了很多常用的类型转换函数。