今天咱們繼續學習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: 小明在說話
複製代碼
參考