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,這句話不會被打印\n");
    } catch (Throwable t) {
        System.out.println("捕獲到JNI拋出的異常(Throwable)又厉,這句話會被打印" + t.getMessage() + "\n");
    }

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

}

C代碼如下:

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

    jclass clz=  (*env)->GetObjectClass(env, jobj);
    //屬性名字不小心寫錯了椎瘟,拿到的是空的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);
    //遇到這句話的時候,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層手動清空異常信息(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);
    //屬性名字不小心寫錯了赞枕,拿到的是空的jfieldID
    jfieldID fid = (*env)->GetFieldID(env, clz, "key1", "Ljava/lang/String;");

    jthrowable err = (*env)->ExceptionOccurred(env);
    if (err != NULL){
        //手動清空異常信息,保證Java代碼能夠繼續(xù)執(zhí)行
        (*env)->ExceptionClear(env);
        //提供補(bǔ)救措施坪创,例如獲取另外一個屬性
        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("程序沒有異常炕婶,這句話會被打印\n");
    } catch (Exception e) {
        System.out.println("沒有捕獲到JNI拋出的異常,這句話不會被打印" + e.getMessage() + "\n");
    }

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

}

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

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

    jthrowable err = (*env)->ExceptionOccurred(env);
    if (err != NULL){
        //手動清空異常信息依沮,保證Java代碼能夠繼續(xù)執(zhí)行
        (*env)->ExceptionClear(env);
        //提供補(bǔ)救措施涯贞,例如獲取另外一個屬性
        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手動拋出了異常宋渔,Java不會繼續(xù)執(zhí)行,這句話不會被打印\n");
    } catch (Exception e) {
        System.out.println("捕獲到JNI手動拋出的異常辜限,這句話會被打踊始稹:" + e.getMessage() + "\n");
    }

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

}

異常處理總結(jié)

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末榆综,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子水评,更是在濱河造成了極大的恐慌吟秩,老刑警劉巖壮池,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異昔榴,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)纺蛆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進(jìn)店門堕伪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來揖庄,“玉大人,你說我怎么就攤上這事欠雌√闵遥” “怎么了?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵富俄,是天一觀的道長禁炒。 經(jīng)常有香客問我,道長霍比,這世上最難降的妖魔是什么齐苛? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮桂塞,結(jié)果婚禮上凹蜂,老公的妹妹穿的比我還像新娘。我一直安慰自己阁危,他們只是感情好玛痊,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著狂打,像睡著了一般擂煞。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上趴乡,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天对省,我揣著相機(jī)與錄音,去河邊找鬼晾捏。 笑死蒿涎,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的惦辛。 我是一名探鬼主播劳秋,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼胖齐!你這毒婦竟也來了玻淑?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤呀伙,失蹤者是張志新(化名)和其女友劉穎补履,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體剿另,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡箫锤,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年帅腌,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片麻汰。...
    茶點(diǎn)故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡速客,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出五鲫,到底是詐尸還是另有隱情溺职,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布位喂,位于F島的核電站浪耘,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏塑崖。R本人自食惡果不足惜七冲,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望规婆。 院中可真熱鬧澜躺,春花似錦、人聲如沸抒蚜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽嗡髓。三九已至操漠,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間饿这,已是汗流浹背浊伙。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留长捧,地道東北人嚣鄙。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像唆姐,于是被迫代替她去往敵國和親拗慨。 傳聞我的和親對象是個殘疾皇子廓八,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容