package org.professor.jni.java; public class TestException { public native void testException(); public void exceptionCallback() { int a = 20 / 0; System.out.println("--->" + a); } } package org.professor.jni; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.widget.TextView; import org.professor.jni.java.TestException; public class MainActivity extends AppCompatActivity { // Used to load the 'native-lib' library on application startup. static { // lib+native-lib+.so //libnative-lib.so System.loadLibrary("hello-jni"); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TextView tv = (TextView) findViewById(R.id.sample_text); // tv.setText(stringFromJNI()); TestException testException = new TestException(); try { testException.testException(); } catch (Exception e) { e.printStackTrace(); } } }
#include <jni.h> #include <android/log.h> #ifndef ANDROIDJNIDEMO_TEST_THROW_EXCEPTION_H #define ANDROIDJNIDEMO_TEST_THROW_EXCEPTION_H #define LOG_D(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) #define LOG_I(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) #define LOG_W(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__) #define LOG_E(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) #ifdef __cplusplus extern "C" { #endif /* * * Class: org_professor_jni_java_TestException * Method: occorException * Signature: ()V */ JNIEXPORT void JNICALL Java_org_professor_jni_java_TestException_testException (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif //ANDROIDJNIDEMO_TEST_THROW_EXCEPTION_H //------分割線 #include <jni.h> #include <test_throw_exception.h> #include <stdio.h> #define LOG_TAG "EXCEPTION" JNIEXPORT void JNICALL Java_org_professor_jni_java_TestException_testException(JNIEnv *env, jobject instance) { jclass exception_clazz = (*env)->FindClass(env, "org/professor/jni/java/TestException"); if (NULL == exception_clazz) { LOG_D("NOT FIND EXCEPTION CLASS"); return; } jmethodID test_method_id = (*env)->GetMethodID(env, exception_clazz, "exceptionCallback", "()V"); if (NULL == test_method_id) { LOG_E("NOT FIND TEXT METHOD ID"); return; } jmethodID default_constructor_method_id = (*env)->GetMethodID(env, exception_clazz, "<init>", "()V"); if (NULL == default_constructor_method_id) { LOG_I("NOT FIND DEFAULT CONSTRUCTOR ID "); return; } jobject test_exception_instance = (*env)->NewObject(env, exception_clazz, default_constructor_method_id); if (NULL == test_exception_instance) { LOG_W("NOT FIND TEST EXCEPTION INSTANCE"); return; } (*env)->CallVoidMethod(env, test_exception_instance, test_method_id); LOG_E("In C: CALL exceptionCallback Method!"); // if ((*env)->ExceptionCheck(env)) { // 檢查JNI調用是否有引起異常 // (*env)->ExceptionDescribe(env); //// (*env)->ExceptionClear(env); // 清除引起的異常,在Java層不會打印異常的堆棧信息 // 若是不清除,後面調用ThrowNew拋出的異常堆棧信息會覆蓋前面的異常信息 //// (*env)->ThrowNew(env, (*env)->FindClass(env, "java/lang/Exception"), "JNI拋出的異常!"); //清除後能夠拋出本身的異常 若是不清除,後面調用ThrowNew拋出的異常堆棧信息會覆蓋前面的異常信息 // //return; // } jthrowable throwable = (*env)->ExceptionOccurred(env); if (NULL != throwable) { (*env)->ExceptionDescribe(env); // (*env)->ExceptionClear(env); } LOG_E("In C: CALL exceptionCallback Method! end"); (*env)->DeleteLocalRef(env, exception_clazz); (*env)->DeleteLocalRef(env, test_exception_instance); }
分析:java
ArithmeticException
exceptionCallback
方法,並對其進行異常檢查(能夠用兩種方法對其進行內存檢查,代碼註釋)。當調用一個JNI函數後,必須先檢查、處理、清除異常後再作其它 JNI 函數調用,不然會產生不可預知的結果。android
一旦發生異常,當即返回,讓調用者處理這個異常。或 調用 ExceptionClear 清除異常,而後執行本身的異常處理代碼。app
異常處理的相關JNI函數總結:ide