JNI 编程上手指南之异常处理

JNI 程序中的异常分为以下几种:

  • Native 程序原生异常,一般通过函数返回值和 linux 信号处理, C++ 中也有 try catch 机制解决异常,不是本文重点
  • JNIEnv 内部函数抛出的异常,一般通过返回值判断,发现异常直接 return, jvm 会给将异常传递给 Java 层
  • Native 回调 Java 层方法,被回调的方法抛出异常,JNI 提供了特定的 API 来处理这类异常

1. JNIEnv 内部函数抛出的异常

很多 JNIEnv 中的函数都会抛出异常,处理方法大体上是一致的:

  • 返回值与特殊值(一般是 NULL)比较,知晓函数是否发生异常
  • 如果发生异常立即 return
  • jvm 会将异常抛给 java 层,我们可以在 java 层通过 try catch 机制捕获异常

接着我们来看一个例子:

Java 层:

public native void exceptionTest();

//调用
try {
     exceptionTest();
} catch (Exception e) {
    e.printStackTrace();
}

Native 层:

extern "C"
JNIEXPORT void JNICALL
Java_com_yuandaima_myjnidemo_MainActivity_exceptionTest(JNIEnv *env, jobject thiz) {   
    //查找的类不存在,返回 NULL;
    jclass clazz = env->FindClass("com/yuandaima/myjnidemo/xxx");
    if (clazz == NULL) {
        return; //return 后,jvm 会向 java 层抛出 ClassNotFoundException
    }
}

执行后的 log:

java.lang.ClassNotFoundException: Didn't find class "com.yuandaima.myjnidemo.xxx"

说明,java 层捕获到了异常

2. Native 回调 Java 层方法,被回调的方法抛出异常

Native 回调 Java 层方法,被回调的方法抛出异常。这样情况下一般有两种解决办法:

  • Java 层 Try catch 本地方法,这是比较推荐的办法。
  • Native 层处理异常,异常处理如果和 native 层相关,可以采用这种方式

2.1 Java 层 Try catch 本地方法

Java 层:

//执行这个方法会抛出异常
private static int exceptionMethod() {
    return 20 / 0;
}

//native 方法,在 native 中,会调用到 exceptionMethod() 方法
public native void exceptionTest();

//Java 层调用
try {
    exceptionTest();
} catch (Exception e) {
    //这里处理异常
    //一般是打 log 和弹 toast 通知用户
    e.printStackTrace();
}

Native 层:

extern "C"
JNIEXPORT void JNICALL
Java_com_yuandaima_myjnidemo_MainActivity_exceptionTest(JNIEnv *env, jobject thiz) {
    jclass clazz = env->FindClass("com/yuandaima/myjnidemo/TestJavaClass");
    if (clazz == NULL) {
        return;
    }

    //调用 java 层会抛出异常的方法
    jmethodID static_method_id = env->GetStaticMethodID(clazz, "exceptionMethod", "()I");

    if (NULL == static_method_id) {
        return;
    }

    //直接调用,发生 ArithmeticException 异常,传回 Java 层
    env->CallStaticIntMethod(clazz, static_method_id);

    env->DeleteLocalRef(clazz);
}

2.2 Native 层处理异常

有的异常需要在 Native 处理,这里又分为两类:

  • 异常在 Native 层就处理完了
  • 异常在 Native 层处理了,还需要返回给 Java 层,Java 层继续处理

接着我们看下示例:

Java 层:

//执行这个方法会抛出异常
private static int exceptionMethod() {
    return 20 / 0;
}

//native 方法,在 native 中,会调用到 exceptionMethod() 方法
public native void exceptionTest();

//Java 层调用
try {
    exceptionTest();
} catch (Exception e) {
    //这里处理异常
    //一般是打 log 和弹 toast 通知用户
    e.printStackTrace();
}

Native 层:

extern "C"
JNIEXPORT void JNICALL
Java_com_yuandaima_myjnidemo_MainActivity_exceptionTest(JNIEnv *env, jobject thiz) {
    jthrowable mThrowable;
    jclass clazz = env->FindClass("com/yuandaima/myjnidemo/TestJavaClass");
    if (clazz == NULL) {
        return;
    }

    jmethodID static_method_id = env->GetStaticMethodID(clazz, "exceptionMethod", "()I");
    if (NULL == static_method_id) {
        return;
    }

    env->CallStaticIntMethod(clazz, static_method_id);

    //检测是否有异常发生
    if (env->ExceptionCheck()) {
        //获取到异常对象
        mThrowable = env->ExceptionOccurred();
        //这里就可以根据实际情况处理异常了
        //.......
        //打印异常信息堆栈
        env->ExceptionDescribe();
        //清除异常信息
        //如果,异常还需要 Java 层处理,可以不调用 ExceptionClear,让异常传递给 Java 层
        env->ExceptionClear();
        //如果调用了 ExceptionClear 后,异常还需要 Java 层处理,我们可以抛出一个新的异常给 Java 层
        jclass clazz_exception = env->FindClass("java/lang/Exception");
        env->ThrowNew(clazz_exception, "JNI抛出的异常!");

        env->DeleteLocalRef(clazz_exception);
    }

    env->DeleteLocalRef(clazz);
    env->DeleteLocalRef(mThrowable);
}
下载说明:
1、本站所有资源均从互联网上收集整理而来,仅供学习交流之用,因此不包含技术服务请大家谅解!
2、本站不提供任何实质性的付费和支付资源,所有需要积分下载的资源均为网站运营赞助费用或者线下劳务费用!
3、本站所有资源仅用于学习及研究使用,您必须在下载后的24小时内删除所下载资源,切勿用于商业用途,否则由此引发的法律纠纷及连带责任本站和发布者概不承担!
4、本站站内提供的所有可下载资源,本站保证未做任何负面改动(不包含修复bug和完善功能等正面优化或二次开发),但本站不保证资源的准确性、安全性和完整性,用户下载后自行斟酌,我们以交流学习为目的,并不是所有的源码都100%无错或无bug!如有链接无法下载、失效或广告,请联系客服处理!
5、本站资源除标明原创外均来自网络整理,版权归原作者或本站特约原创作者所有,如侵犯到您的合法权益,请立即告知本站,本站将及时予与删除并致以最深的歉意!
6、如果您也有好的资源或教程,您可以投稿发布,成功分享后有站币奖励和额外收入!
7、如果您喜欢该资源,请支持官方正版资源,以得到更好的正版服务!
8、请您认真阅读上述内容,注册本站用户或下载本站资源即您同意上述内容!
原文链接:https://www.dandroid.cn/20406,转载请注明出处。
0

评论0

显示验证码
没有账号?注册  忘记密码?