向Native层传递各种参数、由
Native
层返回各种参数
本章涉及的技术要点:
a
、传递空参数,基本类型参数、多个参数,
Java
自定义类对象、不同类型的数组做参数
b
、返回基本类型参数,返回
Java
自定义类对象,返回空
c
、在
JNI
(
C
语言)环境中如何调用
Java
中的方法(得到方法
ID
,执行方法,得到返回值)
d
、在
JNI
(
C
语言)环境如何获取某个
JAVA
自定义对象的成员变量(得到
Field ID,
获取值)
参考文档:
https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/jniTOC.html
请先阅读章节:
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,"","(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,"","(Ldev/mars/jnidemo/SimpleClass;)V");
jobject complexClassObj = env->NewObject(complexClass,complexClassBuildFunctionID,scObj);
return complexClassObj;
}
要点1
:
jint
、
jdouble
等基本类型可以作为
C
语言中的
int
、
double
使用
通过GetMethodID
找到类的构造方法,第一个参数是方法名,但是构造方法是个特例,用
""
表示,第二个参数是方法参数和返回类型的签名
要点2
:创建一个
Java
层对象,先要通过
FindClass
方法找到该类,参数是一个 包名
/
类名 的字符串,包名间的
.
号用
/
代替。
签名参考上述文档中的Type Signature
。如
Java
中对
SimpleClass
构造方法的定义,参数是一个
int
类型,因此签名为
(I),
构造方法的返回值为空,所以签名是
V
,组合在一起就是
(I)V
,如果构造方法有多个参数,每个参数签名用
;
隔开,如果参数是引用类型则在后面必须加上
;
无论后面有没有参数。
NewObject
方法通过
jclass
和
jmethodID
、构造方法参数创建
jobject
对象。
要点3
:要直接修改对象的成员变量(该成员变量可以是
private
的,测试有效,类似
Java
反射),先调用
GetFieldID
方法获取成员变量
ID
,参数如
GetMethodID
,第一个参数是成员变量名,第二个是成员变量的签名。通过
SetShortField
等不同的方法为成员变量赋值。
要点四:在Native
层创建一个复杂对象(对象中包含另一个对象),所用的基本方法在要点
1
、
2
、
3
中有总结。
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,"","()V");
jobject jobject1 = env->NewObject(jclass1,create);
jfieldID privateField = env->GetFieldID(jclass1,"doubleVal","D");
env->SetDoubleField(jobject1,privateField,d);
return jobject1;
}
要点:jni
中对
private
成员变量的修改一样是有效的