JNI:04.缓存策略和异常处理

代码请看:10.JNI基础-缓存策略和异常处理

1. 数组排序:

  • void qsort(void * _Base, size_t _NumOfElements, size_t _SizeOfElements, int(*_PtFuncCompare)(const void *, const void *)) :c中的排序方法
  • jxxx* = env->GetXXArrayElements(env,jarray,NULL);:将java层的数组转换成c层的数组(指针)。
  • (*env)->ReleaseXXArrayElements(env, jarray, xxArray, JNI_OK);:同步数组的数据给 java 数组 xxArray 并不是 jarray。
    1
    2
    3
    // JNI_OK == 0::既要同步数据给 jarray, 又要释放 intArray
    // JNI_COMMIT == 1:会同步数据给 jarray, 但是不会释放 intArray
    // JNI_ABORT == 2:不会同步数据给 jarray, 但是会释放 intArray

native层:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 4. 定义一个 compare 的方法
int compare(const int* number1, const int* number2){
return *number1 - *number2;
}

// 数组排序
JNIEXPORT void JNICALL Java_com_east_jni10_Sample_sort
(JNIEnv* env, jclass jclz, jintArray jarray){

// 2. 获取 jintArray 的首地址
jint* intArray = (*env)->GetIntArrayElements(env,jarray,NULL);

// 3. 获取数组的长度
int length = (*env)->GetArrayLength(env,jarray);

// 1. 对 jarray 进行排序
// void qsort(void * _Base, size_t _NumOfElements, size_t _SizeOfElements, int(*_PtFuncCompare)(const void *, const void *))
// 第一个参数:void* 数组的首地址
// 第二个参数:数组的长度
// 第三个参数:数组元素数据类型的大小
// 第四个参数:数组的一个比较方法指针(Comparable)
qsort(intArray,length,sizeof(int),compare);

// 同步数组的数据给 java 数组 intArray 并不是 jarray, 可以简单理解为 copy
// JNI_OK == 0::既要同步数据给 jarray, 又要释放 intArray
// JNI_COMMIT == 1:会同步数据给 jarray, 但是不会释放 intArray
// JNI_ABORT == 2:不会同步数据给 jarray, 但是会释放 intArray

(*env)->ReleaseIntArrayElements(env, jarray, intArray, JNI_OK);

}

2. 局部引用和全局引用

  • jobject j_str = (*env)->NewObject(env,str_clz,jmid):局部引用对象生成。
  • (*env)->DeleteLocalRef(env,j_str); :删除局部引用
  • jstring globalStr =(*env)->NewGlobalRef(env,value); :创建全局引用
  • (*env)->DeleteGlobalRef(env,globalStr):删除全局引用

2.1. 局部引用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 局部引用
JNIEXPORT void JNICALL Java_com_east_jni10_Sample_localRef
(JNIEnv * env, jclass jclz){
// 在 native 层构建的 Java 对象,不用了应该怎么管理(应该进行回收删除)
// native 层开辟的内存由谁管理,你能开辟多大

// 字符串截取,String 对象
jclass str_clz = (*env)->FindClass(env,"java/lang/String");
jmethodID jmid = (*env)->GetMethodID(env, str_clz, "<init>", "()V");
jobject j_str = (*env)->NewObject(env,str_clz,jmid);

// 还有 100 行代码

// jobject 不要再使用了,要回收 javaGC 的源码
(*env)->DeleteLocalRef(env,j_str);

// 删除了就不能再使用了,C 和 C++ 都需要自己释放内存(静态开辟的不需要,动态开辟的需要)
}

2.2 全局引用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

// 全局引用
jstring globalStr;

JNIEXPORT void JNICALL Java_com_east_jni10_Sample_saveGlobalRef
(JNIEnv * env, jclass j_clz, jstring value){
// 保存全局引用,其它方法需要用到
globalStr = (*env)->NewGlobalRef(env,value);

// NewWeakGlobalRef (java 中的软引用很像)无法保证对象不为空
}

JNIEXPORT jstring JNICALL Java_com_east_jni10_Sample_getGlobalRef
(JNIEnv * env, jclass j_clz){
return globalStr;
}

// 删除全局引用
JNIEXPORT void JNICALL Java_com_east_jni10_Sample_deleteGlobalRef
(JNIEnv * env, jclass j_clz){
(*env)->DeleteGlobalRef(env,globalStr);
}

3. 缓存策略 static, native层有一大堆方法需要去获取 name 属性 // 初始化全局静态缓存

3.1 局部静态缓存

局部静态缓存:即使方法被重复调用也不会反复的给static修饰的字段赋值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
JNIEXPORT void JNICALL Java_com_east_jni10_Sample_staticLocalCache
(JNIEnv * env, jclass j_clz, jstring value){
// name 属性,赋值操作
static jfieldID jfid = NULL; // 局部静态缓存,即使方法被重复调用也不会反复的去获取 jfieldID

if (jfid){
printf("fieldID is not null\n");
}
else{
jfid = (*env)->GetStaticFieldID(env, j_clz, "name", "Ljava/lang/String;");// 如果没有静态缓存 这个方法会被多次调用,会去反复的获取 jfieldID
}

(*env)->SetStaticObjectField(env,j_clz,jfid,value);
}

3.2 全局静态缓存

全局静态缓存:即使方法被重复调用也不会反复的给static修饰的字段赋值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 全局静态缓存
static jfieldID f_name_id = NULL;
static jfieldID f_name1_id = NULL;
static jfieldID f_name2_id = NULL;


JNIEXPORT void JNICALL Java_com_east_jni10_Sample_staticLocalCache
(JNIEnv * env, jclass j_clz, jstring value){
// 因为是静态缓存,所以这个方法被反复调用,也不会反复的去获取 jfieldID
(*env)->SetStaticObjectField(env,j_clz,f_name_id,value);
}


JNIEXPORT void JNICALL Java_com_east_jni10_Sample_initStaticCache
(JNIEnv *env, jclass j_clz){
// 初始化全局静态缓存
f_name_id = (*env)->GetStaticFieldID(env, j_clz, "name", "Ljava/lang/String;");
f_name1_id = (*env)->GetStaticFieldID(env, j_clz, "name1", "Ljava/lang/String;");
f_name2_id = (*env)->GetStaticFieldID(env, j_clz, "name2", "Ljava/lang/String;");
}

4. 异常处理(简单讲,C++异常)

  • jthrowable throwable = (*env)->ExceptionOccurred(env);:正在抛出一个异常的本地引用
  • (*env)->ExceptionClear(env);:清除异常
  • (*env)->Throw(env, throwable);:将ExceptionOccurred获取到的异常直接抛给java层
  • (*env)->ThrowNew(env, no_such_clz, "NoSuchFieldException name3");:抛出自己想抛出的异常

异常说明:

  1. ExceptionCheck 用于检测如果一个异常已经抛出,则该方法将会返回JNI_TRUE就是typedef定义为1的布尔值。

  2. ExceptionOccurred 获取正在抛出一个异常的本地引用,Native或Java层必须处理该异常,并返回一个jthrowable对象。

  3. ExceptionDescribe 主要用于打印出异常的错误描述。

  4. ExceptionClear 清除刚刚抛出的异常。

  5. FatalError 的作用比较特殊,产生一个致命性的错误,Android123提示这样会导致JVM将关闭,就是程序停止运行了,所以使用时要谨慎。

说明下:ExceptionCheck 用法

1
2
3
4
5
6
env->FindClass("Android123CWJ"); //假设这个类本身不存在
if(env->ExceptionCheck())
{
env->ExceptionDescribe();
env->ExceptionClear();
}

下面是:ExceptionOccurred 用法

注意: 保存后在抛出异常后记得 return

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// 异常处理
JNIEXPORT void JNICALL Java_com_east_jni10_Sample_exception
(JNIEnv *env, jclass j_clz){

// 假设现在想给 ,name3 赋值
jfieldID jfid = (*env)->GetStaticFieldID(env, j_clz, "name3", "Ljava/lang/String;");

// 两种方式解决
// 1. 补救措施, 不拿 name3 拿 name
// 1.1 有没有异常
jthrowable throwable = (*env)->ExceptionOccurred(env);
/*if (throwable){
// 补救措施,先把异常清除
printf("native have a exception");
// 清除异常
(*env)->ExceptionClear(env);
// 重新获取 name 属性
jfid = (*env)->GetStaticFieldID(env, j_clz, "name", "Ljava/lang/String;");
}*/

// 2. 想给 java 层抛一个异常
if (throwable){
// 清除异常
(*env)->ExceptionClear(env);
// 给 java 层抛 一个 Throwable 异常

// 第一种方式,直接把异常抛给 java 层
(*env)->Throw(env, throwable);

// 第二种方式抛异常
// (*env)->ThrowNew(env, no_such_clz, "NoSuchFieldException name3");

return; // 必须 return 如果不的话,程序会接着往下运行,肯定还会crash
}

jstring name = (*env)->NewStringUTF(env, "Eastrise");
(*env)->SetStaticObjectField(env, j_clz, jfid, name);

}
-------------本文结束感谢您的阅读-------------
坚持原创技术分享,您的支持将鼓励我继续创作!
0%