Android NDK開發(fā)之旅14--JNI--異常處理

異常處理

異常測試?yán)樱?/p>

public native void testException1();

public static void main(String[] args) {

    JniTest test = new JniTest();

    try {
        test.testException();
        System.out.println("程序無法繼續(xù)執(zhí)行1,這句話不會(huì)被打印\n");
    } catch (Throwable t) {
        System.out.println("捕獲到JNI拋出的異常(Throwable),這句話會(huì)被打印" + t.getMessage() + "\n");
    }

    System.out.println("程序繼續(xù)執(zhí)行2,這句話會(huì)被打印\n");

}

C代碼如下:

//異常處理
JNIEXPORT void JNICALL Java_com_test_JniTest_testException1
(JNIEnv * env, jobject jobj){

    jclass clz=  (*env)->GetObjectClass(env, jobj);
    //屬性名字不小心寫錯(cuò)了,拿到的是空的jfieldID
    jfieldID fid = (*env)->GetFieldID(env, clz, "key1", "Ljava/lang/String;");

    //此處拋出的異常,Java可以通過Throwable來捕獲

    printf("C can run , this will print");
    //這里竟然還可以繼續(xù)執(zhí)行
    jstring key =  (*env)->GetObjectField(env, jobj, fid);
    //遇到這句話的時(shí)候,C程序Crash了
    char* c_str = (*env)->GetStringUTFChars(env, key, NULL);
    printf("C could not run , this will not print");
}

通過例子可以知道,JNI層自己拋出的異常是Error類型,Java可以通過Throwable或者Error來捕獲得到,捕獲異常后Java代碼可以繼續(xù)執(zhí)行下去。

為了確保Java、C/C++代碼可以正常執(zhí)行下去,需要:

在JNI層手動(dòng)清空異常信息(ExceptionClear),保證代碼可以運(yùn)行。
補(bǔ)救措施保證C/C++代碼繼續(xù)運(yùn)行。
例如:

//異常處理
JNIEXPORT void JNICALL Java_com_test_JniTest_testException1
(JNIEnv * env, jobject jobj){
    jclass clz = (*env)->GetObjectClass(env, jobj);
    //屬性名字不小心寫錯(cuò)了,拿到的是空的jfieldID
    jfieldID fid = (*env)->GetFieldID(env, clz, "key1", "Ljava/lang/String;");

    jthrowable err = (*env)->ExceptionOccurred(env);
    if (err != NULL){
        //手動(dòng)清空異常信息,保證Java代碼能夠繼續(xù)執(zhí)行
        (*env)->ExceptionClear(env);
        //提供補(bǔ)救措施,例如獲取另外一個(gè)屬性
        fid = (*env)->GetFieldID(env, clz, "key", "Ljava/lang/String;");
    }


    jstring key = (*env)->GetObjectField(env, jobj, fid);
    char* c_str = (*env)->GetStringUTFChars(env, key, NULL);
}

測試代碼如下:

public static void main(String[] args) {

    JniTest test = new JniTest();

    try {
        test.testException();
        System.out.println("程序沒有異常,這句話會(huì)被打印\n");
    } catch (Exception e) {
        System.out.println("沒有捕獲到JNI拋出的異常,這句話不會(huì)被打印" + e.getMessage() + "\n");
    }

    System.out.println("程序繼續(xù)執(zhí)行,這句話會(huì)被打印\n");

}

用戶可以手動(dòng)通過ThrowNew函數(shù)拋出異常,同樣可以被Java代碼捕獲:

//異常處理
JNIEXPORT void JNICALL Java_com_test_JniTest_testException
(JNIEnv * env, jobject jobj){
    jclass clz = (*env)->GetObjectClass(env, jobj);
    //屬性名字不小心寫錯(cuò)了,拿到的是空的jfieldID
    jfieldID fid = (*env)->GetFieldID(env, clz, "key1", "Ljava/lang/String;");

    jthrowable err = (*env)->ExceptionOccurred(env);
    if (err != NULL){
        //手動(dòng)清空異常信息,保證Java代碼能夠繼續(xù)執(zhí)行
        (*env)->ExceptionClear(env);
        //提供補(bǔ)救措施,例如獲取另外一個(gè)屬性
        fid = (*env)->GetFieldID(env, clz, "key", "Ljava/lang/String;");
    }


    jstring key = (*env)->GetObjectField(env, jobj, fid);
    char* c_str = (*env)->GetStringUTFChars(env, key, NULL);

    //參數(shù)不正確,程序員自己拋出異常,可以在Java中捕獲
    if (_stricmp(c_str,"efg") != 0){
        jclass err_clz = (*env)->FindClass(env, "java/lang/IllegalArgumentException");
        (*env)->ThrowNew(env, err_clz, "key value is invalid!");
    }
}

測試代碼如下:

public static void main(String[] args) {

    JniTest test = new JniTest();

    try {
        test.testException();
        System.out.println("JNI手動(dòng)拋出了異常,Java不會(huì)繼續(xù)執(zhí)行,這句話不會(huì)被打印\n");
    } catch (Exception e) {
        System.out.println("捕獲到JNI手動(dòng)拋出的異常,這句話會(huì)被打印:" + e.getMessage() + "\n");
    }

    System.out.println("程序繼續(xù)執(zhí)行,這句話會(huì)被打印\n");

}

異常處理總結(jié)

JNI自己拋出的異常,是Error類型,Java可以通過Throwable或者Error來捕獲得到,捕獲異常后Java代碼可以繼續(xù)執(zhí)行下去。在C層可以清空(ExceptionClear),保證try中的代碼Java代碼繼續(xù)執(zhí)行,并且最好要提供補(bǔ)救措施,確保JNI層代碼正常繼續(xù)運(yùn)行。
用戶通過ThrowNew手動(dòng)拋出的異常,同樣可以在Java層捕捉得到。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容