一般会有两种异常
- Native 层代码出现的异常.
- Native 层调用 Java 层代码时, Java 层出现异常
第一种又分为两种解决方案, 分别是在 Native 层自己处理, 进行补救. 或者是将异常抛出到 Java 层, 由Java 层进行处理.
下面先是第一种方式的处理, 包含了两种解决方案.
Java 层代码, 这里是使用 Kotlin 写的
binding.sampleText.setOnClickListener{
//方式1, 在 Native 层进行处理
exceptionFromJNI1()
//执行完JNI 后, Toast一下值
Toast.makeText(this, name1, Toast.LENGTH_SHORT).show()
//方式2, 在 Native 层进行抛出, java 层处理
try {
exceptionFromJNI2()
}catch (e:NoSuchFieldException){
e.printStackTrace()
Log.e("Error", "---------------------异常捕获-----")
}
// exceptionFromJNI3()
}
Native 代码
extern "C"
JNIEXPORT void JNICALL Java_com_aaatest_study003_MainActivity_exceptionFromJNI1(JNIEnv *env, jobject thiz) {
//故意制造异常
jclass pJclass = env->GetObjectClass(thiz);
jfieldID f_id = env->GetFieldID(pJclass, "name999", "Ljava/lang/String;");
//检测本次执行有没有异常
jthrowable occurred = env->ExceptionOccurred();
if(occurred) { //非0, 表示有异常
_MY_LOGE("C++层中出现了异常");
env->ExceptionClear(); //清除异常
//尝试补救
jfieldID f_id = env->GetFieldID(pJclass, "name1", "Ljava/lang/String;");
//获取值
jstring jstr = (jstring) env->GetObjectField(thiz, f_id);
const char * c_str = env->GetStringUTFChars(jstr, nullptr);
//修改值
char new_char[40] = "name1 = ";
strcat(new_char, c_str);
//将 c 字符串转为 jni 字符串
jstring str_jni_new = env->NewStringUTF(new_char);
env->SetObjectField(thiz, f_id, str_jni_new);
//释放
env->ReleaseStringUTFChars(jstr, c_str);
_MY_LOGE("开始补救, 值为:%s",new_char);
}
}
extern "C"
JNIEXPORT void JNICALL Java_com_aaatest_study003_MainActivity_exceptionFromJNI2(JNIEnv *env, jobject thiz) {
//故意制造异常
jclass pJclass = env->GetObjectClass(thiz);
jfieldID f_id = env->GetFieldID(pJclass, "name999", "Ljava/lang/String;");
jthrowable occurred = env->ExceptionOccurred();
if(occurred) {
//先清除异常,
env->ExceptionClear();
//抛出
jclass exceptionClz = env->FindClass("java/lang/NoSuchFieldException");
env->ThrowNew(exceptionClz, "没有找到字段 name888");
}
}
接着是第二种异常处理的解决方案, 主要是由 Native 调用 java 方法时出现异常.
Java 代码
//写给C++调用的函数, 在java 层制造异常
public fun show(){
throw NullPointerException()
Log.e("Error", "---------------------java 层 show 方法抛出异常-----")
}
Native 代码
extern "C"
JNIEXPORT void JNICALL Java_com_aaatest_study003_MainActivity_exceptionFromJNI3(JNIEnv *env, jobject thiz) {
//被动处理异常, JNI 代码没有问题. java 代码有问题.
jclass objectClass = env->GetObjectClass(thiz);
jmethodID methodId = env->GetMethodID(objectClass, "show", "()V");
env->CallVoidMethod(thiz, methodId);
//在怀疑java会有问题的地方, 紧跟以下代码. 不要在中间插入其他代码.
if(env->ExceptionCheck()) {
env->ExceptionDescribe(); //输出异常信息
env->ExceptionClear();
}
}