如何在JNI中抛异常

在android的JNIHelp.h文件中声明四种可以向JVM抛异常的函数:
int jniThrowException(JNIEnv* env,  const char* className, const char* msg)
int jniThrowNullPointerException(JNIEnv* env,  char* msg)
int jniThrowIOException(JNIEnv* env,  int errnum)
int jniThrowRuntimeException(JNIEnv* env,  const char* msg)
注意虽然  const char* className 它是字符串,但是它是要传到中使用,所以它必须和某个类相对应的。
以上4个函数的定义是JNIHelp.c文件中进行的。查看源码你会发现 jniThrowNullPointerException jniThrowRuntimeException jniThrowIOException 其实就是个特殊的jniThrowException其实它们是const char* className 参数分别为" java/lang/NullPointerException "、 "java/lang/RuntimeException "、" java/IO/IOException "的jniThrowException。
它们的使用也很简单,具体可以参照下面的示例代码。
另外注意,这里的抛异常函数并不是在抛异常的同时退出当前函数,而是在函数最终返回时,才真正的抛出异常。
示例1
android_database_SQLiteQuery.cpp文件中的native_fill_window函数
static jint  native_fill_window(JNIEnv* env, jobject object, jobject javaWindow,  jint  startPos,  jint  offsetParam)
{
//略
    if (statement == NULL) {
        LOGE("Invalid statement in fillWindow()");
        jniThrowException(env, "java/lang/IllegalStateException",
                          "Attempting to access a deactivated, closed, or empty cursor");
         return  0;
    }

    // Only do the binding if there is a valid offsetParam. If no binding needs to be done
    // offsetParam will be set to 0, an invliad value.
     if (offsetParam > 0) {
        // Bind the offset parameter, telling the program which row to start with
        err = sqlite3_bind_int(statement, offsetParam, startPos);
         if  (err != SQLITE_OK) {
            LOGE("Unable to bind offset position, offsetParam = %d", offsetParam);
            jniThrowException(env, "java/lang/IllegalArgumentException",
                              sqlite3_errmsg(GET_HANDLE(env, object)));
             return  0;
        }
        LOG_WINDOW("Bound to startPos %d", startPos);
    } else {
        LOG_WINDOW("Not binding to startPos %d", startPos);
    }

    // Get the native window
    window = get_window_from_object(env, javaWindow);
    if (!window) {
        LOGE("Invalid CursorWindow");
         jniThrowException(env, "java/lang/IllegalArgumentException","Bad CursorWindow");
         return  0;
    }
    LOG_WINDOW("Window: numRows = %d, size = %d, freeSpace = %d", window->getNumRows(), window->size(), window->freeSpace());

    numColumns = sqlite3_column_count(statement);
    if (!window->setNumColumns(numColumns)) {
        LOGE("Failed to change column count from %d to %d", window->getNumColumns(), numColumns);
         jniThrowException(env, "java/lang/IllegalStateException", "numColumns mismatch");
         return  0;
    }
//略    
}
示例2
android_util_EventLog.cpp中的android_util_EventLog_readEvents函数
static void android_util_EventLog_readEvents(JNIEnv* env, jobject clazz,
                                             jintArray tags,
                                             jobject out) {
    if (tags == NULL || out == NULL) {
         jniThrowException(env, "java/lang/NullPointerException", NULL);
         return;
    }

    int fd = open("/dev/" LOGGER_LOG_EVENTS, O_RDONLY | O_NONBLOCK);
     if (fd < 0) {
         jniThrowIOException(env, errno);
        return;
    }

    jsize tagLength = env->GetArrayLength(tags);
    jint *tagValues = env->GetIntArrayElements(tags, NULL);

    uint8_t buf[LOGGER_ENTRY_MAX_LEN];
    struct timeval timeout = {0, 0};
    fd_set readset;
    FD_ZERO(&readset);

     for (;;) {
        // Use a short select() to try to avoid problems hanging on read().
        // This means we block for 5ms at the end of the log -- oh well.
        timeout.tv_usec = 5000;
        FD_SET(fd, &readset);
         int r = select(fd + 1, &readset, NULL, NULL, &timeout);
        if (r == 0) {
            break;  // no more events
        } else if (r < 0 && errno == EINTR) {
            continue;  // interrupted by signal, try again
        } else if (r < 0) {
             jniThrowIOException(env, errno);  // Will throw on return
            break;
        }

        int len = read(fd, buf, sizeof(buf));
        if (len == 0 || (len < 0 && errno == EAGAIN)) {
            break;  // no more events
        } else if (len < 0 && errno == EINTR) {
            continue;  // interrupted by signal, try again
        } else if (len < 0) {
             jniThrowIOException(env, errno);  // Will throw on return
            break;
        } else if ((size_t) len < sizeof(logger_entry) + sizeof(int32_t)) {
             jniThrowException(env, "java/io/IOException", "Event too short");
            break;
        }
//略
    }
    close(fd);
    env->ReleaseIntArrayElements(tags, tagValues, 0);
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
第1章 Android平台上的C++入门 1.1 Microsoft Windows 1.1.1 在Windows平台上下载并安装JDK开发包 1.1.2 在Windows平台上下载并安装ApacheANT 1.1.3 在Windows平台上下载并安装AndroidSDK 1.1.4 在Windows平台上下载并安装Cygwin 1.1.5 在Windows平台上下载并安装AndroidNDK 1.1.6 在Windows平台上下载并安装Eclipse 1.2 AppleMacOSX 1.2.1 在Mac平台上安装Xcode 1.2.2 验证Mac平台的Java开发包 1.2.3 验证Mac平台上的ApacheANT 1.2.4 验证GNUMake 1.2.5 在Mac平台上下载并安装AndroidSDK 1.2.6 在Mac平台上下载并安装AndroidNDK 1.2.7 在Mac平台上下载并安装Eclipse 1.3 UbuntuLinux 1.3.1 检查GNUC库版本 1.3.2 激活在64位系统上支持32位的功能 1.3.3 在Linux平台上下载并安装Java开发工具包(JDK) 1.3.4 在Linux平台上下载并安装ApacheANT 1.3.5 在Linux平台上下载并安装GNUMake 1.3.6 在Linux平台上下载并安装AndroidSDK 1.3.7 在Linux平台上下载并安装AndroidNDK 1.3.8 在Linux平台上下载并安装Eclipse 1.4 下载并安装ADT 1.4.1 安装Android平台包 1.4.2 配置模拟器 1.5 小结 第2章 深入了解AndroidNDK 2.1 AndroidNDK提供的组件 2.2 AndroidNDK的结构 2.3 以一个示例开始 2.3.1 指定AndroidNDK的位置 2.3.2 导入示例项目 2.3.3 向项目添加原生支持 2.3.4 运行项目 2.3.5 用命令行对项目进行构建 2.3.6 检测AndroidNDK项目的结构 2.4 构建系统 2.4.1 Android.mk 2.4.2 Application.mk 2.5 使用NDK-Build脚本 2.6 排除构建系统故障 2.7 小结 第3章 用JNI实现与原生代码通信 3.1 什么是JNI 3.2 以一个示例开始 3.2.1 原生方法的声明 3.2.2 加载共享库 3.2.3 实现原生方法 3.3 数据类型 3.3.1 基本数据类型 3.3.2 引用类型 3.4 对引用数据类型的操作 3.4.1 字符串操作 3.4.2 数组操作 3.4.3 NIO操作 3.4.4 访问域 3.4.5 调用方法 3.4.6 域和方法描述符 3.5 异常处理 3.5.1 捕获异常 3.5.2 异常 3.6 局部和全局引用 3.6.1 局部引用 3.6.2 全局引用 3.6.3 弱全局引用 3.7 线程 3.7.1 同步 3.7.2 原生线程 3.8 小结 第4章 使用SWIG自动生成JNI代码 4.1 什么是SWIG 4.2 安装 4.2.1 Windows平台上SWIG的安装 4.2.2 在MacOSX下安装 4.2.3 在UbuntuLinux下安装 4.3 通过示例程序试用SWIG 4.3.1 接口文件 4.3.2 在命令行方式下调用SWIG 4.3.3 将SWIG集成到Android构建过程 4.3.4 更新Activity. 4.3.5 执行应用程序 4.3.6 剖析生成的代码 4.4 封装C语言代码 4.4.1 全局变量 4.4.2 常量 4.4.3 只读变量 4.4.4 枚举 4.4.5 结构体 4.4.6 指针 4.5 封装C++代码 4.5.1 指针、引用和值 4.5.2 默认参数 4.5.3 重载函数 4.5.4 类 4.6 异常处理 4.7 内存管理 4.8 从原生代码调用Java 4.8.1 异步通信 4.8.2 启用Directors 4.8.3 启用RTTI 4.8.4 重写回调方法 4.8.5 更新HeIIojniActivity 4.9 小结 第5章 日志、调试及故障处理 5.1 日志 5.1.1 框架 5.1.2 原生日志API 5.1.3 受控制的日志 5.1.4 控制台日志 5.2 调试 5.2.1 预备知识 5.2.2 调试会话建立 5.2.3 建立调试示例 …… 第6章 BionicAPI入门 第7章 原生线程 第8章 POSIXSocketAPI:面向连接的通信 第9章 POSIXSocketAPI:无连接的通信 第10章 POSIXSocketAPI:本地通信 第11章 支持C++ 第12章 原生图形API 第13章 原生音频API 第14章 程序概要分析和NEON优化

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值