Android C++系列:JNI调用时的异常处理

简介: Native 提供了 ExceptionOccurred 和 ExceptionCheck 方法来检测是否有异常发生,前者返回的是 jthrowable 类型,后者返回的是 jboolean 类型。

image.png


Android JNI 调用时的异常主要有如下两种:


  • Native 代码调用 Java 层代码时发生了异常要处理
  • Native 代码自己抛出了一个异常让 Java 层去处理 可以看到异常的发生和处理基本都需要 Native 和 Java 交互,而对于 Native 自身出了异常,也就是 C/C++ 代码有问题,导致应用崩溃的又是另一回事了。


Native 调用 Java 方法时的异常


之前讲述了如何从 Native 调用 Java 的方法,先准备一个有异常的方法供 Native 去调用。


private int exceptionFun() {      return 2 / 0;    }                   


然后在 Native 中调用该方法:


jclass cls = env->FindClass("com/qingkouwei/Demo");
      jmethodID mid = env->GetMethodID(cls, "<init>", "()V");
      jobject obj = env->NewObject(cls, mid);
      mid = env->GetMethodID(cls, "exceptionFun", "()I");
      // 先初始化一个类,然后调用类方法,就如文章中描述的那样
      env->CallIntMethod(obj, mid);


除数为 0 ,一调用应用直接崩溃了。


java.lang.ArithmeticException: divide by zero              


接下来就是要进行异常处理的部分了。


jclass cls = env->FindClass("com/qingkouwei/Demo");
      jmethodID mid = env->GetMethodID(cls, "<init>", "()V");
      jobject obj = env->NewObject(cls, mid);
      mid = env->GetMethodID(cls, "exceptionFun", "()I");
  // 先初始化一个类,然后调用类方法,就如博客中描述的那样
      env->CallIntMethod(obj, mid);
      //检查是否发生了异常
      jthrowable exc = env->ExceptionOccurred();
  //    jboolean result = env->ExceptionCheck();
      if (exc) {
          // 打印异常日志
          env->ExceptionDescribe();
          // 这行代码才是关键不让应用崩溃的代码,
          env->ExceptionClear();
          // 发生异常了要记得释放资源
          env->DeleteLocalRef(cls);
          env->DeleteLocalRef(obj);
      }


添加如上代码进行处理后,应用并不会直接崩溃了,并且在 LogCat 中会看到对应的异常日志,这里面到了做了哪些操作呢?


Native 提供了 ExceptionOccurred 和 ExceptionCheck 方法来检测是否有异常发生,前者返回的是 jthrowable 类型,后者返回的是 jboolean 类型。


如果有异常,会通过 ExceptionDescribe 方法来打印异常信息,方便我们在 LogCat 中看到对应的信息。


而 ExceptionClear 方法则是关键的不会让应用直接崩溃的方法,类似于 Java 的 catch 捕获异常处理,它会消除这次异常。


这样就把由 Native 调用 Java 时的一个异常进行了处理,当处理完异常之后,别忘了释放对应的资源。


不过,我们这样仅仅是消除了这次异常,还应该让调用者有异常的发生,那么就需要通过 Native 来抛出一个异常告诉 Java 调用者了。


Native 抛出 Java 中的异常


有时在 Native 代码中进行一些操作,需要抛出异常到 Java ,交由上层去处理。


比如 Java 调用 Native 方法传递了某个参数,而这个参数有问题,那么 Native 就可以抛出异常让 Java 去处理这个参数异常的问题。


Native 抛出异常的代码大致都是相同的,可以抽出一个通用函数来:


void throwByName(JNIEnv *env, const char *name, const char *msg) {
      jclass cls = env->FindClass(name);
      if (cls != NULL) {
          env->ThrowNew(cls, msg);
      }
      env->DeleteLocalRef(cls);
  }
  // 调用抛出异常
  extern "C"
  JNIEXPORT void JNICALL
  Java_com_qingkouwei_Demo_nativeThrowException(JNIEnv *env, jobject instance) {
      throwByName(env, "java/lang/IllegalArgumentException", "native throw exception");
  }


根据异常类型和异常信息来抛出异常。


而在 Java 中,就必须要用 try … catch… 来准备好捕获这次异常了。


try {
              nativeThrowException();
          } catch (IllegalArgumentException e) {
              Log.e("NativeMethod", e.getMessage());
          }


小结


除了以上两种异常情况之外,还有一个特别常见的异常,就是当判断某个变量为 NULL 之后,执行立即返回的操作。


当发生异常时,一定要先处理异常,然后才能继续执行后面的步骤。如果不是需要立即返回的,那么就通过 ExceptionClear清除这次异常,然后在进行其他的处理。


对于在 Native 中发生了异常,需要让 Java 层去处理了,则在 Native 中抛出对应的异常,由 Java 层去捕获,比如在使用 ExceptionClear 清除了异常之后,就可以通过 throwNew 来抛出异常信息。


具体的异常处理方法和时机还是要看具体的使用场景,选择最合适的处理方法。

目录
相关文章
|
3月前
|
C++
C++ 语言异常处理实战:在编程潮流中坚守稳定,开启代码可靠之旅
【8月更文挑战第22天】C++的异常处理机制是确保程序稳定的关键特性。它允许程序在遇到错误时优雅地响应而非直接崩溃。通过`throw`抛出异常,并用`catch`捕获处理,可使程序控制流跳转至错误处理代码。例如,在进行除法运算或文件读取时,若发生除数为零或文件无法打开等错误,则可通过抛出异常并在调用处捕获来妥善处理这些情况。恰当使用异常处理能显著提升程序的健壮性和维护性。
74 2
|
3月前
|
Java Android开发 C++
Android Studio JNI 使用模板:c/cpp源文件的集成编译,快速上手
本文提供了一个Android Studio中JNI使用的模板,包括创建C/C++源文件、编辑CMakeLists.txt、编写JNI接口代码、配置build.gradle以及编译生成.so库的详细步骤,以帮助开发者快速上手Android平台的JNI开发和编译过程。
234 1
|
5月前
|
Java API C++
Java JNI开发时常用数据类型与C++中数据类型转换
Java JNI开发时常用数据类型与C++中数据类型转换
211 0
|
6月前
|
安全 C++
C++中的异常处理与错误处理机制
C++中的异常处理与错误处理机制
72 0
|
2月前
|
Java Android开发 C++
🚀Android NDK开发实战!Java与C++混合编程,打造极致性能体验!📊
在Android应用开发中,追求卓越性能是不变的主题。本文介绍如何利用Android NDK(Native Development Kit)结合Java与C++进行混合编程,提升应用性能。从环境搭建到JNI接口设计,再到实战示例,全面展示NDK的优势与应用技巧,助你打造高性能应用。通过具体案例,如计算斐波那契数列,详细讲解Java与C++的协作流程,帮助开发者掌握NDK开发精髓,实现高效计算与硬件交互。
129 1
|
4月前
|
Java Android开发 C++
🚀Android NDK开发实战!Java与C++混合编程,打造极致性能体验!📊
【7月更文挑战第28天】在 Android 开发中, NDK 让 Java 与 C++ 混合编程成为可能, 从而提升应用性能。**为何选 NDK?** C++ 在执行效率与内存管理上优于 Java, 特别适合高性能需求场景。**环境搭建** 需 Android Studio 和 NDK, 工具如 CMake。**JNI** 构建 Java-C++ 交互, 通过声明 `native` 方法并在 C++ 中实现。**实战** 示例: 使用 C++ 计算斐波那契数列以提高效率。**总结** 混合编程增强性能, 但增加复杂性, 使用前需谨慎评估。
140 4
|
3月前
|
JSON Android开发 C++
Android c++ core guideline checker 应用
Android c++ core guideline checker 应用
|
3月前
|
JSON Android开发 数据格式
Android c++ core guideline checker 应用问题之JSON compilation database的定义如何解决
Android c++ core guideline checker 应用问题之JSON compilation database的定义如何解决
|
3月前
|
IDE 开发工具 Android开发
Android c++ core guideline checker 应用问题之clang-tidy 检查后发现的问题如何解决
Android c++ core guideline checker 应用问题之clang-tidy 检查后发现的问题如何解决
|
3月前
|
算法 Java Linux
Intellij Java JNI 调用 C++
Intellij Java JNI 调用 C++
38 0