Android JNI學習-異常處理

異常咱們已經很熟悉了,空指針、數組越界等等,在Java中,當拋出一個異常,虛擬機會中止執行代碼塊並進入調用棧反向檢查能處理特定異常的異常處理程序代碼塊,虛擬機清除異常並將控制權交給異常處理程序。而JNI不一樣,JNI沒有像Java同樣有try…catch…final這樣的異常處理機制,面且在本地代碼中調用某個JNI接口時若是發生了異常,後續的本地代碼不會當即中止執行,而會繼續往下執行後面的代碼,這就要求開發人員在異常發生後顯式地實現異常處理。java

1 捕獲異常

在一個方法執行以後,能夠調用(*env)->ExceptionCheck或者 (*env)->ExceptionOccurred(二者的區別在於返回值不同)數組

ExceptionCheck:檢查是否發生了異常,如有異常返回JNI_TRUE,不然返回JNI_FALSE ExceptionOccurred:檢查是否發生了異常,若用異常返回該異常的引用,不然返回NULLbash

const jchar *cstr = (*env)->GetStringChars(env, jstr);
     if (c_str == NULL) {
         return; 
     }
     if ((*env)->ExceptionCheck(env)) { /* 異常檢查 */
         (*env)->ReleaseStringChars(env, jstr, cstr); // 發生異常後釋放分配內存
         return; 
     }
複製代碼

2 拋出異常

ThrowNew:在當前線程觸發一個異常,並自定義輸出異常信息 jint (JNICALL *ThrowNew) (JNIEnv *env, jclass clazz, const char *msg);函數

Throw:丟棄一個現有的異常對象,在當前線程觸發一個新的異常 jint (JNICALL *Throw) (JNIEnv *env, jthrowable obj);ui

FatalError:致命異常,用於輸出一個異常信息,並終止當前VM實例(即退出程序) void (JNICALL *FatalError) (JNIEnv *env, const char *msg);spa

3 示例

jclass jclass1 = (*env)->FindClass(env, "com/test/JNIController");
    if (jclass1 == 0) {
        return;
    }

    jmethodID methodID = (*env)->GetMethodID(env, jclass1, "exitProcessCallBack", "(III)V");
    if (methodID == 0) {
        return;
    }

    (*env)->CallVoidMethod(env, local_object, methodID, code, uploaded, all);

    if ((*env)->ExceptionCheck){
        (*env)->ExceptionDescribe(env);     // 打印異常的堆棧信息 
        (*env)->ExceptionClear(env);        // 清除異常堆棧信息 
        (*env)->ThrowNew(env,(*env)->FindClass(env,"java/lang/Exception"),"JNI出現異常!");
    }
複製代碼

4 總結

  1. 當調用一個JNI函數後,必須先檢查、處理、清除異常後再作其它 JNI 函數調用,不然會產生不可預知的結果。
  2. 一旦發生異常,當即返回,讓調用者處理這個異常。或 調用 ExceptionClear 清除異常,而後執行本身的異常處理代碼。
相關文章
相關標籤/搜索