Android JNI开发系列:第四章 异常处理

    xiaoxiao2025-07-11  21

    项目代码:https://github.com/VincentWei95/ndk

    Android JNI开发系列:第一章 JNIEnv接口指针

    Android JNI开发系列:第二章 数据类型

    Android JNI开发系列:第三章 对引用数据类型的操作

    Android JNI开发系列:第四章 异常处理

    Android JNI开发系列:第五章 局部和全局引用

    Android JNI开发系列:第六章 线程

    Android JNI开发系列:第七章 POSIX线程

    Android JNI开发系列:第八章 POSIX Socket API 面向连接的通信

    Android JNI开发系列:第九章 POSIX Socket API 无连接的通信

    Android JNI开发系列:第十章 POSIX Socket API 本地通信

    在java中,当抛出一个异常时,虚拟机停止执行代码块并进入调用栈反向检查能处理特定类型异常的异常处理程序代码块,也就是捕获异常。虚拟机清除异常并将控制权交给异常处理程序。

    相比之下,JNI要求开发人员在异常发生后显示地实现异常处理流。

    1 捕获异常

    public class JavaClass { // 调用throwingMethod()时从JNI中捕获异常 private void throwingMethod() throws NullPointException { throw new NullPointException(); } private native void accessMethods(); } jthrowable ex; ... (*env)->CallVoidMethod(env, instance, throwingMethodId); // JNI提供了ExceptionOccurred函数查询虚拟机中是否有挂起的异常 ex = (*env)->ExceptionOccurred(env); if (ex != 0) { // 使用完之后ExceptionClear函数清除异常 (*env)->ExceptionClear(env); }

    2 抛出异常

    因为异常是java类,应该先用FindClass函数找到异常类,再用 ThrowNew 函数初始化抛出异常。

    jclazz clazz; ... clazz = (*env)->FindClass(env, "java/lang/NullPointerException"); if (clazz != 0) { (*env)->ThrowNew(env, clazz, "Exception message"); }

    注意:因为原生函数代码执行不受虚拟机控制,因此抛出异常并不会停止原生函数的执行并把控制权转交给异常处理程序。所以在原生代码抛出异常时,应该释放所有已分配的原生资源。

    3 异常demo

    com_example_ndk_JNITest.h /* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_example_ndk_JNITest */ #ifndef _Included_com_example_ndk_JNITest #define _Included_com_example_ndk_JNITest #ifdef __cplusplus extern "C" { #endif /* * Class: com_example_ndk_JNITest * Method: accessExceptionMethod * Signature: ()V */ JNIEXPORT void JNICALL Java_com_example_ndk_JNITest_accessExceptionMethod (JNIEnv *, jobject); /* * Class: com_example_ndk_JNITest * Method: throwExceptionMethod * Signature: ()V */ JNIEXPORT void JNICALL Java_com_example_ndk_JNITest_throwExceptionMethod (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif com_example_ndk_JNITest.c #include "/include/com_example_ndk_JNITest.h" #include <jni.h> #include <stdio.h> #include <syslog.h> /* * Class: com_example_ndk_JNITest * Method: accessExceptionMethod * Signature: ()V */ JNIEXPORT void JNICALL Java_com_example_ndk_JNITest_accessExceptionMethod (JNIEnv *env, jobject object) { // 获取java class jclass clazz = (*env)->GetObjectClass(env, object); // 获取class中的方法id jmethodID methodId = (*env)->GetMethodID(env, clazz, "throwingExceptionMethod", "()V"); // 调用java中的方法 (*env)->CallVoidMethod(env, object, methodId); // 检查调用的方法是否发生异常 jthrowable exception = (*env)->ExceptionOccurred(env); if (exception != 0) { // 函数发生异常,检查完后清除异常 syslog(LOG_ERR, "native catch exception"); (*env)->ExceptionClear(env); } } /* * Class: com_example_ndk_JNITest * Method: throwExceptionMethod * Signature: ()V */ JNIEXPORT void JNICALL Java_com_example_ndk_JNITest_throwExceptionMethod (JNIEnv *env, jobject object) { jclass exceptionClazz = (*env)->FindClass(env, "java/lang/NullPointerException"); if (exceptionClazz != 0) { (*env)->ThrowNew(env, exceptionClazz, "native throw null pointer exception!"); } } JNITest.java package com.example.ndk; public class JNITest { // 抛出异常方法 private void throwingExceptionMethod() { throw new NullPointerException("native access throw null pointer exception!"); } static { System.loadLibrary("ndk"); } public native void accessExceptionMethod(); public native void throwExceptionMethod(); } JniActivity.java package com.example.ndk; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); JNITest jniTest = new JNITest(); jniTest.accessExceptionMethod(); try { jniTest.throwExceptionMethod(); } catch (Exception e) { e.printStackTrace(); } } }
    最新回复(0)