JNI 中的異常處理

一般會有兩種異常

  1. Native 層代碼出現的異常.
  2. 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();
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章