NDK开发 从入门到放弃(五:JNI抛异常)

前言

在C++的代码运行过程中,若是发生异常错误,需要抛出异常在Java代码中来处理。JNI函数中有ThrowThrowNew两个方式来抛出异常。在第四节(《NDK开发 从入门到放弃(四:JNI函数、C与C++调用函数的区别)》)我们简单介绍了这两个函数,这里将以实例来稍微讲解一下。

简单实例

这里我们实现如下功能:函数获取字符串的长度,若字符串为null对象,则使用Throw抛出NullPointerException异常,当字符串长度为5时,使用ThrowNew抛出IllegalArgumentException异常,否则返回实际长度。

public class JNIDynamicUtils {
    /**
     * 调用C++代码的方法,当字符串为null或长度为5时抛出异常,否则,返回该字符串的长度
     * @return
     */
    public static native int getStrLength(String str) throws NullPointerException, IllegalArgumentException;

    /**
     * 加载so库或jni库
     */
    static {
        System.loadLibrary("JNI_DYNAMIC_ANDROID_TEST");
    }
}
#include <stdio.h>
#include <jni.h>
#include <stdlib.h>

// C++层 native函数
jint getLengthOfStr(JNIEnv *env, jclass clazz, jstring str) {
    if (str == NULL) {
        // 抛出空指针异常
        jclass clz = env->FindClass("java/lang/NullPointerException");
        jmethodID methodId = env->GetMethodID(clz, "<init>", "()V");
        jthrowable throwable = (jthrowable) env->NewObject(clz, methodId);
        env->Throw(throwable);
    } else {
        jint len = env->GetStringUTFLength(str);
        if (len == 5) {
            // 抛出IllegalArgumentException异常
            env->ThrowNew(env->FindClass("java/lang/IllegalArgumentException"), "this is IllegalArgumentException error form C++, because the str length is 5");
        } else {
            return len;
        }
    }
}

/**
 * JNINativeMethod由三部分组成:
 * (1)Java中的函数名;
 * (2)函数签名,格式为(输入参数类型)返回值类型;
 *  (Ljava/lang/String;)I  I表示返回值为int型,(Ljava/lang/String;)表示需要一个String参数
 * (3)native函数名
 */
static JNINativeMethod gMethods[] = { 
    {"getStrLength", "(Ljava/lang/String;)I", (void *) getLengthOfStr }
 };

//System.loadLibrary过程中会自动调用JNI_OnLoad,在此进行动态注册
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
    JNIEnv *env = NULL;
    jint result = JNI_FALSE;

    //获取env指针
    if (jvm->GetEnv((void**) &env, JNI_VERSION_1_6) != JNI_OK) {
        return result;
    }
    if (env == NULL) {
        return result;
    }
    //获取类引用
    jclass clazz = env->FindClass("<包名>/JNIDynamicUtils");
    if (clazz == NULL) {
        return result;
    }
    //注册方法
    if (env->RegisterNatives(clazz, gMethods, sizeof(gMethods) / sizeof(gMethods[0])) < 0) {
        return result;
    }
    //成功
    result = JNI_VERSION_1_6;
    return result;
}
private void dynamicJniGetStrLength(String str) {
    // tvInfo为界面上的一个TextView控件
    try {
        tvInfo.setText(tvInfo.getText().toString() + "\n" + "--->dynamic jni: " + JNIDynamicUtils.getStrLength(str));
    } catch (NullPointerException e) {
        tvInfo.setText(tvInfo.getText().toString() + "\n" + "--->dynamic jni:" + e);
    } catch (IllegalArgumentException e) {
        tvInfo.setText(tvInfo.getText().toString() + "\n" + "--->dynamic jni:" + e);
    }
}

如上代码,我们在C++函数中,根据不同的条件抛出不同的异常或返回正常的结果。当点击按钮时,触发dynamicJniGetStrLength方法(该方法将调用native方法,且获取返回信息显示),用如下代码测试:

dynamicJniGetStrLength(null);
dynamicJniGetStrLength("hello world");
dynamicJniGetStrLength("hello");

这里写图片描述

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值