Java的编程中,我们经常会遇到各种的异常,也会处理各种的异常。处理异常在java中非常简单,我们通常会使用try-catch-finally来处理,也可以使用throw简单抛出一个异常。那么在jni编程的时候我们又是如何处理异常的呢?

异常处理流程

jni规范已经给我们做好了所有需要做的事情。回想一下处理异常的过程:

  1. 我们首先要在有可能产生异常的地方检测异常
  2. 处理异常 
    是的,我觉得异常的处理就是可以简单的总结为两步,在异常处理中我们通常会打印栈信息等。在jni编程中,异常处理的思路应该也与之类似,过程可用下图表示: 
     
    在jni中我么需要手动清除异常。因此,jni中异常的处理应该严格遵循:检查->处理->清除的流程,在图中我把清除也认为是处理的其中一步了。

JNI中异常处理函数

jni.h中有如下相关的函数的定义:

    jint        (*Throw)(JNIEnv*, jthrowable);
jint (*ThrowNew)(JNIEnv *, jclass, const char *);
jthrowable (*ExceptionOccurred)(JNIEnv*);
void (*ExceptionDescribe)(JNIEnv*);
void (*ExceptionClear)(JNIEnv*);
void (*FatalError)(JNIEnv*, const char*);

此外,还有一个函数和他们没放在一起:

    jboolean    (*ExceptionCheck)(JNIEnv*);

单从名字上我们可以知道用于检测异常的发生的函数有:

  • (ExceptionCheck)(JNIEnv);
  • (ExceptionOccurred)(JNIEnv); 
    用于清理异常的有:
  • (ExceptionClear)(JNIEnv); 
    用于跑出异常的有:
  • (Throw)(JNIEnv, jthrowable);
  • (ThrowNew)(JNIEnv , jclass, const char *);
  • (FatalError)(JNIEnv, const char*); 
    下面对以上函数做一个简单的介绍: 
    1> ExceptionCheck:检查是否发生了异常,若有异常返回JNI_TRUE,否则返回JNI_FALSE 
    2> ExceptionOccurred:检查是否发生了异常,若用异常返回该异常的引用,否则返回NULL 
    3> ExceptionDescribe:打印异常的堆栈信息 
    4> ExceptionClear:清除异常堆栈信息 
    5> ThrowNew:在当前线程触发一个异常,并自定义输出异常信息 
    6> Throw:丢弃一个现有的异常对象,在当前线程触发一个新的异常 
    7> FatalError:致命异常,用于输出一个异常信息,并终止当前VM实例(即退出程序)

测试异常

根据以上总结,我们写如下功能的测试代码: 
native调用java中的方法,java中的方法抛出异常,我们在native中检测异常,检测到后抛出native中的异常,并清理异常。

c代码

void native_catchException(JNIEnv *env, jobject obj)
{
jthrowable exc;
jclass cls = (*env)->GetObjectClass(env, obj);
jmethodID mid =(*env)->GetMethodID(env, cls, "callbackException", "()V");
if (mid == NULL) {
return;
}
(*env)->CallVoidMethod(env, obj, mid);
exc = (*env)->ExceptionOccurred(env);
if (exc) {
jclass newExcCls;
(*env)->ExceptionDescribe(env);
(*env)->ExceptionClear(env);
newExcCls = (*env)->FindClass(env,"java/lang/IllegalArgumentException");
if (newExcCls == NULL) {
/* Unable to find the exception class, give up. */
return;
}
(*env)->ThrowNew(env, newExcCls, "thrown from C code");
}
} static JNINativeMethod gMethods[] = {
...
{"exception","()V",(void *)native_catchException},
};

代码的其他部分请参看之前的章节。

java代码

    protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.text);
try {
exception();
} catch (Exception e) {
System.out.println("In Java:\n\t" + e);
}
}
private native void exception() throws IllegalArgumentException;
private void callbackException() throws NullPointerException {
throw new NullPointerException("MainActivity.callbackException");
}

输出

09-26 10:58:50.012 23934-23934/com.jinwei.jnitesthello W/System.err: java.lang.NullPointerException: MainActivity.callbackException
09-26 10:58:50.012 23934-23934/com.jinwei.jnitesthello W/System.err: at com.jinwei.jnitesthello.MainActivity.callbackException(MainActivity.java:24)
09-26 10:58:50.012 23934-23934/com.jinwei.jnitesthello W/System.err: at com.jinwei.jnitesthello.MainActivity.exception(Native Method)
09-26 10:58:50.012 23934-23934/com.jinwei.jnitesthello W/System.err: at com.jinwei.jnitesthello.MainActivity.onCreate(MainActivity.java:32)
09-26 10:58:50.013 23934-23934/com.jinwei.jnitesthello W/System.err: at android.app.Activity.performCreate(Activity.java:6299)
09-26 10:58:50.013 23934-23934/com.jinwei.jnitesthello W/System.err: at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1107)
09-26 10:58:50.013 23934-23934/com.jinwei.jnitesthello W/System.err: at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2369)
09-26 10:58:50.013 23934-23934/com.jinwei.jnitesthello W/System.err: at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476)
09-26 10:58:50.013 23934-23934/com.jinwei.jnitesthello W/System.err: at android.app.ActivityThread.-wrap11(ActivityThread.java)
09-26 10:58:50.013 23934-23934/com.jinwei.jnitesthello W/System.err: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344)
09-26 10:58:50.013 23934-23934/com.jinwei.jnitesthello W/System.err: at android.os.Handler.dispatchMessage(Handler.java:102)
09-26 10:58:50.013 23934-23934/com.jinwei.jnitesthello W/System.err: at android.os.Looper.loop(Looper.java:148)
09-26 10:58:50.013 23934-23934/com.jinwei.jnitesthello W/System.err: at android.app.ActivityThread.main(ActivityThread.java:5417)
09-26 10:58:50.013 23934-23934/com.jinwei.jnitesthello W/System.err: at java.lang.reflect.Method.invoke(Native Method)
09-26 10:58:50.013 23934-23934/com.jinwei.jnitesthello W/System.err: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:731)
09-26 10:58:50.013 23934-23934/com.jinwei.jnitesthello W/System.err: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:621)
09-26 10:58:50.013 23934-23934/com.jinwei.jnitesthello I/System.out: In Java:
09-26 10:58:50.013 23934-23934/com.jinwei.jnitesthello I/System.out: java.lang.IllegalArgumentException: thrown from C code

从输出中我们看到c代码中使用:(*env)->ThrowNew(env, newExcCls, “thrown from C code”);这行代码跑出了异常。然后java中的异常处理函数打印了栈的信息。

工具函数

JNI中抛异常很经典:找异常类,调用ThrowNew抛出之;所以,可以写一个工具函数。

void
JNU_ThrowByName(JNIEnv *env, const char *name, const char *msg)
{
jclass cls = (*env)->FindClass(env, name);
/* if cls is NULL, an exception has already been thrown */
if (cls != NULL) {
(*env)->ThrowNew(env, cls, msg);
}
/* free the local ref */
(*env)->DeleteLocalRef(env, cls);
}

Android jni/ndk编程五:jni异常处理的更多相关文章

  1. Android之NDK编程(JNI)

    转自:http://www.cnblogs.com/xw022/archive/2011/08/18/2144621.html NDK编程入门--C回调JAVA方法   一.主要流程 1.  新建一个 ...

  2. Delphi使用android的NDK是通过JNI接口,封装好了,不用自己写本地代码,直接调用

    一.Android平台编程方式:      1.基于Android SDK进行开发的第三方应用都必须使用Java语言(Android的SDK基于Java实现)      2.自从ndk r5发布以后, ...

  3. Android Studio NDK编程初探

    继上一篇学习了如何使用NDK编译FFMPEG后,接下来就是要学习如何在Android Studio中使用了. 经过参考和一系列的摸索,记录下具体步骤. 创建C++ Support的Android St ...

  4. Android JNI&NDK编程小结及建议

    前言 由于网上关于JNI/NDK相关的知识点介绍的比较零散而且不具备参照性,所以写了这篇JNI/NDK笔记,便于作为随时查阅的工具类型的文章,本文主要的介绍了在平时项目中常用的命令.JNI数据类型.签 ...

  5. Android jni/ndk编程二:jni数据类型转换(primitive,String,array)

    一.数据类型映射概述 从我们开始jni编程起,就不可能避开函数的参数与返回值的问题.java语言的数据类型和c/c++有很多不同的地方,所以我们必须考虑当在java层调用c/c++函数时,怎么正确的把 ...

  6. Android之NDK环境配置+JNI开发+so文件编译

    前言 这边Android作为日常记录,虽然破坏了文章队形~   最近人工智能挺火的,也稍微了解了一些库,比如关于视觉库openCV.要在安卓下调用这些C/C++库,需要用到JNI开发,在此把过程分享一 ...

  7. Android Studio Ndk 编程

    如今开发Android程序基本都已经从Eclipse转到了Android Studio了, 近期项目需求, 须要用到ndk编程, 于是就折腾了一下. 开发环境 Android Studio 1.5.1 ...

  8. Android Studio JNI/NDK 编程简介(一)

    首先说一下概念及相关的东西: JNI : JNI是Java Native Interface的缩写,它提供了若干的API实现了Java和其他语言的通信(主要是C&C++).从Java1.1开始 ...

  9. Android Studio JNI/NDK 编程(二) Windows 下环境搭建 demo 开发

    环境 windows 8  (注:其实 Linux 开发可能更方便) Android Studio 2.1; 一 . 下载 安装android-ndk开发包 地址:链接:http://pan.baid ...

随机推荐

  1. 【玩转SpringBoot】通过事件机制参与SpringBoot应用的启动过程

    生命周期和事件监听 一个应用的启动过程和关闭过程是归属到“生命周期”这个概念的范畴. 典型的设计是在启动和关闭过程中会触发一系列的“事件”,我们只要监听这些事件,就能参与到这个过程中来. 要想监听事件 ...

  2. Qt5配置winpCap

    在网上查了很多资料,搞了差不多一天总算解决Qt5使用winPcap配置的问题了!记录一下 以便后续忘记 1.下载winpcap4.1.3,百度即可搜索到 2.下载winpCap开发者工具包http:/ ...

  3. nginx反向代理局域网访问外网

    .配置内网hosts vim /etc/hosts 添加 host1(能连外网的服务器ip)   central.maven.org 2.在host1 服务器上nginx配置 server {    ...

  4. STM32/EMC/ZILIAO

    https://www.st.com/content/ccc/resource/technical/document/application_note/a2/9c/07/d9/2a/b2/47/dc/ ...

  5. Mac上 intellij IDEA报错:Class JavaLaunchHelper is implemented in both /Library/Java/JavaVirtualMachines/jdk .jdk/Contents/Home/bin/java ( ) and /Library/Java/JavaVirtualMachines/jdk

    解决方案: 点击IDEA菜单里的Help-Edit Custom Properties,没有这个properties文件的话,会提示创建,在里面加上 idea.no.launcher=true 说明: ...

  6. javascript基本语法点

    1. getElementById例:<input type="text" id="user" />则getElementById('user'). ...

  7. JMeter函数整理

    "_intSum” 功能:用于计算多个整数的和,可以是计算正整数和负整数的和,它有N个参数,最少有3个参数,最多不限.最后一个参数是函数名称,前面的其它参数是要求和的整数.这个函数在函数对话 ...

  8. String成员函数

    string类提供的各种操作函数大致分为八类:构造器和析构器,大小和容量,元素存取,字符串比较,字符串修改,字符串接合,I/O操作以及搜索和查找. 函数名称 功能 构造函数 产生或复制字符串 析构函数 ...

  9. 解决Android无法正常https://dl.google.com/dl/android/maven2/com/的办法

    最近需要进行移动开发,在安装Android Studio时,遇到了很纠结的问题,安装一直很不顺利.经过2天的百度搜索终于是找到解决的办法. 问题花了2天的时间才从茫茫大海中找到确切的答案.所以必须开个 ...

  10. 【leetcode】1278. Palindrome Partitioning III

    题目如下: You are given a string s containing lowercase letters and an integer k. You need to : First, c ...