一般會有兩種異常
- 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();
}
}