今天咱们继续学习JNI数组,此篇文章仅做为笔记,以防之后忘记java
JNI把java类型分为俩类,基本数据类型和引用数据类型,引用数据类型统一用jobject来表示,数组也同样,也分为基本数据类型和引用数据类型,引用数据类型为jobjectarray来表示android
咱们先来分析一下基本数据类型的数组相关的API数组
返回一个基本数据类型的数组,其中PrimitiveType
指的是基本数据类型,好比你要获取int的数据类型的数组,那么PrimitiveType
就是int缓存
NativeType *Get<PrimitiveType>ArrayElements(JNIEnv *env,
ArrayType array, jboolean *isCopy);
复制代码
*isCopy
为JNI_TRUE时,指针指向原数组的拷贝,*isCop
为JNI_FALSE时,指针指向原数组若是函数指针指向原数组,那么全部的修改都是在原数组上进行的,若是函数指针指向拷贝数组,那么全部的修改都是在拷贝数组上进行的,元素组不受影响ide
我么你须要保证当拷贝发生了,修改的数据能够同步到原数组,Release<PrimitiveType>ArrayElements
就是这个做用函数
void Release<PrimitiveType>ArrayElements(JNIEnv *env,
ArrayType array, NativeType *elems, jint mode);
复制代码
0
表示把修改同步到原数组,并释放本地数组 JNI_COMMIT
:把修改同步到原数组,可是不释放本地数组 JNI_ABORT
:不把修改同步到原数组,可是释放本地数组当Get< PrimitiveType >ArrayElements函数不发生拷贝,那么mode不起任何做用post
java代码学习
public class TextJniArray {
static {
System.loadLibrary("textjniarray");
}
public native void textArray(int[] array);
}
复制代码
C代码ui
#include <jni.h>
#include <android/log.h>
static void native_text_array(JNIEnv *env, jobject jobject1, jintArray array) {
//获取数组长度
jsize length = env->GetArrayLength(array);
//获取本地数组
jint *native_intaray = env->GetIntArrayElements(array, NULL);
//操做本地数组
for(int i=0;i<length;i++){
native_intaray[i]+=100;
}
//释放本地数组
env->ReleaseIntArrayElements(array,native_intaray,0);
}
static const JNINativeMethod nativeMethod[] = {
{"textArray", "([I)V", (void *) native_text_array}
};
static int registNativeMethod(JNIEnv *env) {
int result = -1;
jclass class_text = env->FindClass("com.taobao.alinnkit.ndk1.TextJniArray");
if (env->RegisterNatives(class_text, nativeMethod,
sizeof(nativeMethod) / sizeof(nativeMethod[0])) == JNI_OK) {
result = 0;
}
return result;
}
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv *env = NULL;
int result = -1;
if (vm->GetEnv((void **) &env, JNI_VERSION_1_1) == JNI_OK) {
if (registNativeMethod(env) == JNI_OK) {
result = JNI_VERSION_1_6;
}
return result;
}
}
复制代码
调用this
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
int[] a = {0, 1, 2, 3, 4, 5};
for (int i = 0; i < 6; i++) {
Log.d("mmm调用前数组数据", a[i] + "/");
}
new TextJniArray().textArray(a);
for (int i = 0; i < 6; i++) {
Log.d("mmm调用后数组数据", a[i] + "/");
}
}
复制代码
打印
D/mmm调用前数组数据: 0/
D/mmm调用前数组数据: 1/
D/mmm调用前数组数据: 2/
D/mmm调用前数组数据: 3/
D/mmm调用前数组数据: 4/
D/mmm调用前数组数据: 5/
D/mmm调用后数组数据: 100/
D/mmm调用后数组数据: 101/
D/mmm调用后数组数据: 102/
D/mmm调用后数组数据: 103/
D/mmm调用后数组数据: 104/
D/mmm调用后数组数据: 105/
复制代码
void Get<PrimitiveType>ArrayRegion(JNIEnv *env, ArrayType array,
jsize start, jsize len, NativeType *buf);
复制代码
这个函数的做用是拷贝java数组ArrayType array
到本地数组NativeType *buf
,若是在本地数组上修改,须要同步到java数组,那么须要调用Set<PrimitiveType>ArrayRegion
void Set<PrimitiveType>ArrayRegion(JNIEnv *env, ArrayType array,
jsize start, jsize len, const NativeType *buf);
复制代码
这个函数的做用是把本地数组NativeType *buf
数据写回到java原数组中,起始点为start,长度为len
此次只贴C代码
static void native_text_array1(JNIEnv *env, jobject jobject1, jintArray array) {
//获取数组长度
jsize length = env->GetArrayLength(array);
//建立本地缓存数组
jint native_array[length - 2];
//进行数组考别
env->GetIntArrayRegion(array, 2, length - 2, native_array);
for (int i = 0; i < length - 2; ++i) {
native_array[i] += 100;
}
//把修改数据写回原数组
env->SetIntArrayRegion(array, 2, length - 2, native_array);
}
复制代码
打印
D/mmm调用前数组数据: 0/
D/mmm调用前数组数据: 1/
D/mmm调用前数组数据: 2/
D/mmm调用前数组数据: 3/
D/mmm调用前数组数据: 4/
D/mmm调用前数组数据: 5/
D/mmm调用后数组数据: 0/
D/mmm调用后数组数据: 1/
D/mmm调用后数组数据: 102/
D/mmm调用后数组数据: 103/
D/mmm调用后数组数据: 104/
D/mmm调用后数组数据: 105/
复制代码
这个方法能够在JNI层建立数组,而后返回给java
C代码
static jintArray native_text_array2(JNIEnv *env, jobject jobject1) {
jintArray array = env->NewIntArray(2);
jint *native_array = env->GetIntArrayElements(array, NULL);
for (int i = 0; i < 2; ++i) {
native_array[i] = 100 + i;
}
env->ReleaseIntArrayElements(array, native_array, 0);
return array;
}
复制代码
调用
int[] a = new TextJniArray().textArray2();
for (int i = 0; i < 2; i++) {
Log.d("mmm数组数据", a[i] + "/");
}
复制代码
打印
D/mmm数组数据: 100/
D/mmm数组数据: 101/
复制代码
先看下须要用的API
jobject GetObjectArrayElement(JNIEnv *env, jobjectArray array, jsize index);
复制代码
获取数组array
在索引index
下的元素
jboolean IsInstanceOf(JNIEnv *env, jobject obj, jclass clazz);
复制代码
用于判断对象obj,是否是class类的实例对象
准备引用数据类型
public class Person {
public String name;
public Person(String name) {
this.name = name;
}
public void say() {
Log.d("mmm", name + "在说话");
}
}
复制代码
准备native方法
public native void textArray3(Person[] persons);
复制代码
准备C实现
static void native_text_array3(JNIEnv *env, jobject jobject1, jobjectArray jobjectArray1) {
//获取数组长度
jsize length = env->GetArrayLength(jobjectArray1);
//获取person的class对象
jclass jclass_person = env->FindClass("com.taobao.alinnkit.ndk1.Person");
if (jclass_person == NULL) {
return;
}
//获取方法
jmethodID jmethodId_say = env->GetMethodID(jclass_person, "say", "()V");
if (jmethodId_say == NULL) {
return;
}
for (int i = 0; i < length; ++i) {
//获取java引用数组中的元素
jobject jobject2 = env->GetObjectArrayElement(jobjectArray1, i);
//判断元素的类型
if (env->IsInstanceOf(jobject2, jclass_person)) {
//调用元素的方法
env->CallVoidMethod(jobject2, jmethodId_say);
}
}
}
复制代码
调用
Person[] people = new Person[2];
people[0] = new Person("jj");
people[1] = new Person("oj");
new TextJniArray().textArray3(people);
复制代码
打印数据
D/mmm: jj在说话
D/mmm: oj在说话
复制代码
jobjectArray NewObjectArray(JNIEnv *env, jsize length, jclass elementClass, jobject initialElement);
复制代码
做用是在JNI层建立引用微数据类型数组,NewObjectArray
函数会根据elementClass
类型建立一个长度length
的引用数据类型数组
若是指定第四个参数则会初始化数组,若是指定为NULL,则数组的全部元素为null
void SetObjectArrayElement(JNIEnv *env, jobjectArray array, jsize index, jobject value);
复制代码
为数组array,设置索引index下的值为value
jobject NewObject(JNIEnv *env, jclass clazz, jmethodID methodID, ...);
jobject NewObjectA(JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args);
jobject NewObjectV(JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);
复制代码
这三个参数区别就是传入的参数不同,可是做用同样
FindClass
来寻找GetMethodID
来获取,传入的参数名为<init>
,参数名的返回值为Vjobject AllocObject(JNIEnv *env, jclass clazz);
复制代码
这个函数会给clazz类的对象分配内存,而不用调用class类的构造函数,并返回一个执向这个对象的引用
准备java的native方法
public native Person[] textArray4(int length);
复制代码
准备C实现
static jobjectArray native_text_array4(JNIEnv *env, jobject jobject1, jint length) {
jclass jclass_person = env->FindClass("com.taobao.alinnkit.ndk1.Person");
if (jclass_person == NULL) {
return NULL;
}
//获取person的构造方法
jmethodID jmethodId_gouzao = env->GetMethodID(jclass_person, "<init>", "(Ljava/lang/String;)V");
if (jmethodId_gouzao == NULL) {
return NULL;
}
//建立引用数组
jobjectArray array_person = env->NewObjectArray(length, jclass_person, NULL);
for (int i = 0; i < length; ++i) {
jobject person = NULL;
if (i == 0) {
//构造方法建立对象
person = env->NewObject(jclass_person, jmethodId_gouzao, env->NewStringUTF("小红"));
}
if (i == 1) {
person = env->AllocObject(jclass_person);
//直接分配内存
jmethodID setname = env->GetMethodID(jclass_person, "setName", "(Ljava/lang/String;)V");
env->CallVoidMethod(person, setname, env->NewStringUTF("小明"));
}
//把初始化好的对象赋值给数组
env->SetObjectArrayElement(array_person, i, person);
//释放局部变量
env->DeleteLocalRef(person);
}
return array_person;
}
复制代码
调用
Person[] people1 = new TextJniArray().textArray4(2);
for (int i = 0; i < people1.length; i++) {
people1[i].say();
}
复制代码
打印数据
D/mmm: 小红在说话
D/mmm: 小明在说话
复制代码
参考