分享

NDK学习(一),向Native层传递各种参数、由Native层返回各种参数

 instl 2018-10-09
向Native层传递各种参数、由Native层返回各种参数
本章涉及的技术要点:
a、传递空参数,基本类型参数、多个参数,Java自定义类对象、不同类型的数组做参数
b、返回基本类型参数,返回Java自定义类对象,返回空
c、在JNIC语言)环境中如何调用Java中的方法(得到方法ID,执行方法,得到返回值)
d、在JNIC语言)环境如何获取某个JAVA自定义对象的成员变量(得到Field ID,获取值)
 
请先阅读章节:JNI Types and Data Structures
本章用到的Java代码:
 
1、向native层传入多个多种参数,返回一个Java层的复杂对象(复杂对象中有另一个Java对象)
首先在Java层定义native接口
public native ComplexClass generateComplexObject(int i,short s,long l,float f,double d,char c,byte byteVal,boolean b);
参数中共定义了8中基本类型,以及要在native层利用这些参数返回一个Complex对象。
 
Native实现:
JNIEXPORT jobject JNICALL
Java_dev_mars_jnidemo_NativeBridge_generateComplexObject(JNIEnv *env, jobject instance, jint i,
                                                         jshort s, jlong l, jfloat f, jdouble d,
                                                         jchar c, jbyte byteVal, jboolean b) {
    // TODO
    jclass simpleClass = env->FindClass("dev/mars/jnidemo/SimpleClass");
    jmethodID simpleClassBuildFunctionID = env->GetMethodID(simpleClass,"<init>","(I)V");
    jobject scObj = env->NewObject(simpleClass,simpleClassBuildFunctionID,i);
    jfieldID shortField = env->GetFieldID(simpleClass,"shortVal","S");
    jfieldID doubleField = env->GetFieldID(simpleClass,"doubleVal","D");
    jfieldID floatField = env->GetFieldID(simpleClass,"floatVal","F");
    jfieldID longField = env->GetFieldID(simpleClass,"longVal","J");
    jfieldID charField = env->GetFieldID(simpleClass,"charVal","C");
    jfieldID byteField = env->GetFieldID(simpleClass,"byteVal","B");
    jfieldID boolField = env->GetFieldID(simpleClass,"boolVal","Z");
    env->SetLongField(scObj,longField,l);
    env->SetFloatField(scObj,floatField,f);
    env->SetDoubleField(scObj,doubleField,d);
    env->SetCharField(scObj,charField,c);
    env->SetByteField(scObj,byteField,byteVal);
    env->SetBooleanField(scObj,boolField,b);

    jclass complexClass =env->FindClass("dev/mars/jnidemo/ComplexClass");
    jmethodID complexClassBuildFunctionID = env->GetMethodID(complexClass,"<init>","(Ldev/mars/jnidemo/SimpleClass;)V");
    jobject complexClassObj = env->NewObject(complexClass,complexClassBuildFunctionID,scObj);
    return complexClassObj;
}
 
要点1jintjdouble等基本类型可以作为C语言中的intdouble使用
通过GetMethodID找到类的构造方法,第一个参数是方法名,但是构造方法是个特例,用"<init>"表示,第二个参数是方法参数和返回类型的签名
要点2:创建一个Java层对象,先要通过FindClass方法找到该类,参数是一个 包名/类名 的字符串,包名间的.号用/代替。
签名参考上述文档中的Type Signature。如Java中对SimpleClass构造方法的定义,参数是一个int类型,因此签名为(I),构造方法的返回值为空,所以签名是V,组合在一起就是(I)V,如果构造方法有多个参数,每个参数签名用;隔开,如果参数是引用类型则在后面必须加上;无论后面有没有参数。
NewObject方法通过jclassjmethodID、构造方法参数创建jobject对象。
要点3:要直接修改对象的成员变量(该成员变量可以是private的,测试有效,类似Java反射),先调用GetFieldID方法获取成员变量ID,参数如GetMethodID,第一个参数是成员变量名,第二个是成员变量的签名。通过SetShortField等不同的方法为成员变量赋值。
要点四:在Native层创建一个复杂对象(对象中包含另一个对象),所用的基本方法在要点123中有总结。
 
2、向native层传入数组,并返回一个数组(数组类型以int为例,其他类型可以推导)
Java:
public native int[] getIntArray(int[] sourceArray);
Native:
JNIEXPORT jintArray JNICALL
Java_dev_mars_jnidemo_NativeBridge_getIntArray(JNIEnv *env, jobject instance,
                                               jintArray sourceArray_) {

    jint *sourceArray = env->GetIntArrayElements(sourceArray_, NULL);
    // TODO
    LOGE("print source array:");
    for (int i = 0; i < env->GetArrayLength(sourceArray_); i++) {
        LOGE("source array[%d] = %d", i, *(sourceArray + i));
    }
    env->ReleaseIntArrayElements(sourceArray_, sourceArray, 0);

    //generate new array
    jintArray newJintArray = env->NewIntArray(3);
    jint newArray[] = {1,2,3};
    env->SetIntArrayRegion(newJintArray,0,3,newArray);
    return newJintArray;
}
 
要点1:GetIntArrayElements可以将jintArray 转换jint *指针,通过该指针可以打印传入的数组
要点2:要构造一个新的jintArray 可以用NewIntArray(jsize)方法,然后定义一个jint数组,通过SetIntArrayRegion方法将jint数组赋值给jintArray
3、通过native层改变Java对象的私有成员变量
public native PrivateFieldClass alterPrivateField(double d);

native层实现:
JNIEXPORT jobject JNICALL
Java_dev_mars_jnidemo_NativeBridge_alterPrivateField(JNIEnv *env, jobject instance, jdouble d) {
    jclass jclass1 = env->FindClass("dev/mars/jnidemo/PrivateFieldClass");
    jmethodID create = env->GetMethodID(jclass1,"<init>","()V");
    jobject jobject1 = env->NewObject(jclass1,create);
    jfieldID privateField = env->GetFieldID(jclass1,"doubleVal","D");
    env->SetDoubleField(jobject1,privateField,d);
    return jobject1;
}
 
要点:jni中对private成员变量的修改一样是有效的

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多