1.非静态缓存案例分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
extern "C"
JNIEXPORT void JNICALL
Java_com_jack_as_1jni_1project_MainActivity2_localCache(JNIEnv *env, jclass clazz, jstring name) {

// 非静态缓存
jfieldID f_id = nullptr;

if (f_id == nullptr) {
// 每次调用localCache方法都会获取一次jfieldID,如果频繁调用该方法会影响性能
f_id = env->GetStaticFieldID(clazz, "name1", "Ljava/lang/String;");
} else {
LOGE("空的");
}

env->SetStaticObjectField(clazz, f_id, name); // 修改 AAA

f_id = nullptr;
}

2. 静态缓存

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
40
41
42
43
44
45
46
47
//1.在方法外定义需要静态缓存的变量
static jfieldID f_name1_id = nullptr;
static jfieldID f_name2_id = nullptr;
static jfieldID f_name3_id = nullptr;
static jfieldID f_name4_id = nullptr;
static jfieldID f_name5_id = nullptr;
static jfieldID f_name6_id = nullptr;

// 2.初始化缓存变量,
// 先缓存。此方法应该在java构造方法中调用
extern "C"
JNIEXPORT void JNICALL
Java_com_jack_as_1jni_1project_MainActivity2_initStaticCache(JNIEnv *env, jclass clazz) {
f_name1_id = env->GetStaticFieldID(clazz, "name1", "Ljava/lang/String;");
f_name2_id = env->GetStaticFieldID(clazz, "name2", "Ljava/lang/String;");
f_name3_id = env->GetStaticFieldID(clazz, "name3", "Ljava/lang/String;");
f_name4_id = env->GetStaticFieldID(clazz, "name4", "Ljava/lang/String;");
f_name5_id = env->GetStaticFieldID(clazz, "name5", "Ljava/lang/String;");
f_name6_id = env->GetStaticFieldID(clazz, "name6", "Ljava/lang/String;");
}

// 3.使用缓存变量
// 使用
extern "C"
JNIEXPORT void JNICALL
Java_com_jack_as_1jni_1project_MainActivity2_staticCache(JNIEnv *env, jclass clazz, jstring name) {
// 不会反复 GetStaticFieldID 提供性能
env->SetStaticObjectField(clazz, f_name1_id, name);
env->SetStaticObjectField(clazz, f_name2_id, name);
env->SetStaticObjectField(clazz, f_name3_id, name);
env->SetStaticObjectField(clazz, f_name4_id, name);
env->SetStaticObjectField(clazz, f_name5_id, name);
env->SetStaticObjectField(clazz, f_name6_id, name);
}

// 4.清除缓存变量
// 清除,此方法应该在onDestory中调用
extern "C"
JNIEXPORT void JNICALL
Java_com_jack_as_1jni_1project_MainActivity2_clearStaticCache(JNIEnv *env, jclass clazz) {
f_name1_id = nullptr;
f_name2_id = nullptr;
f_name3_id = nullptr;
f_name4_id = nullptr;
f_name5_id = nullptr;
f_name6_id = nullptr;
}

3. Native异常监测

3.1 方法内部补救

native方法中监控异常,如果有的话就处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
extern "C"
JNIEXPORT void JNICALL
Java_com_derry_as_1jni_1project_MainActivity3_exception(JNIEnv *env, jclass clazz) {
// 假设现在想操作 name999 ,没有name999就会在native层奔溃掉
jfieldID f_id = env->GetStaticFieldID(clazz, "name999", "Ljava/lang/String;");

// 方式1 补救措施
// 监测本次执行,到底有没有异常 JNI函数里面代码有问题
jthrowable thr = env->ExceptionOccurred();

if(thr) { // 非0 进去,监测到有异常
LOGD("C++层有异常 监测到了");

env->ExceptionClear(); // 此异常被清除

// 开始 补救措施
jfieldID f_id = env->GetStaticFieldID(clazz, "name1", "Ljava/lang/String;");
}
}
3.2 向java层抛异常
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
extern "C"
JNIEXPORT void JNICALL
Java_com_derry_as_1jni_1project_MainActivity3_exception2(JNIEnv *env, jclass clazz) {
// 假设现在想操作 name999 ,没有name999就会在native层奔溃掉
jfieldID f_id = env->GetStaticFieldID(clazz, "name8888", "Ljava/lang/String;");

// 方式2 往Java层抛

jthrowable jthrowable = env->ExceptionOccurred(); // 监测本次执行,到底有没有异常 JNI函数里面代码有问题

if(jthrowable) { // 非0 进去,监测到有异常
LOGD("C++层有异常 监测到了");

env->ExceptionClear(); // 此异常被清除

// Throw抛一个 Java的对象 java/lang/String java/xxxxx/xxx/NullExxx
jclass clz = env->FindClass("java/lang/NoSuchFieldException");
env->ThrowNew(clz, "NoSuchFieldException 实在是找不到");
}
}
3.3 Native监控java抛的异常
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
// java直接抛异常
public static void show() throws Exception {
Log.d("jack", "show: 1111");
Log.d("jack", "show: 1111");
Log.d("jack", "show: 1111");

throw new NullPointerException("我是Java中抛出的异常,我的show方法里面发送了Java逻辑错误");
}

extern "C"
JNIEXPORT void JNICALL
Java_com_Jack_as_1jni_1project_MainActivity3_exception3(JNIEnv *env, jclass clazz) {
jmethodID showID = env->GetStaticMethodID(clazz, "show", "()V");
// 会不会立马崩溃?
// 不会,只是CallStaticVoidMethod调用引起的,但是不会崩溃,因为ExceptionCheck()会监测此处崩溃,并且打出日志
env->CallStaticVoidMethod(clazz, showID);

// ExceptionCheck 《==》 慢慢的奔溃的,相当于给了你空余时间,既然不是马上奔溃,我就可以检测

// JNI函数里面代码有问题 没有问题,给你空余时间,慢慢的奔溃的
if (env->ExceptionCheck()) {
env->ExceptionDescribe(); // 输出描述 信息
env->ExceptionClear(); // 此异常被清除 业务逻辑控制
}

// 注意实现:
/*// 奔溃后,下面的语句,照样打印
LOGI("C++层>>>>>>>>>>>>>>>>>>>>>>>>>>>>1");
LOGI("C++层>>>>>>>>>>>>>>>>>>>>>>>>>>>>2");
LOGI("C++层>>>>>>>>>>>>>>>>>>>>>>>>>>>>3");

env->NewStringUTF("AAAA"); // 局部引用 崩溃被消除*/
}