NDK-异常处理与动态注册

NDK异常处理

jni异常一般发生在C调用java方法的时候,分为两种情况

  • 当我们使用JNIEnv获取jclass、jmethod等出现了类不存在、方法不存在等
  • 当我们在native层调用的java方法内部出现异常的时候

异常处理方法

检查异常

我们可以使用ExceptionCheck()方法判断是否出现了异常,如果出现了异常,会返回true。

使用ExceptionClear()则会清除异常,让程序继续执行下去,当然,也可以使用ExceptionDescribe(),这个方法会在日志中打印异常堆栈

jfieldID jfieldId = env->GetFieldID(thiz, "testEx", "I");
if(env->ExceptionCheck()){
    LOGD("异常发生了");
    env->ExceptionDescribe();
    env->ExceptionClear();
}

也可以使用ExceptionOccurred()方法判断,如果出现了异常,则会返回jthrowable对象,否则返回NULL

jthrowable jthrowable1 = env->ExceptionOccurred();
if (jthrowable1) {
    env->ExceptionClear();
}

主动抛出异常

我们也可以使用ThrowNew()方法主动抛出异常,参数一是异常的jclass对象

env->ThrowNew(env->FindClass("java/lang/Exception"), "native ex");

注意:ThrowNew()抛出的异常在java层可以try catch到

NDK函数注册

NDK静态注册

通过函数名去匹配对应的native方法,格式如下

JNIEXPORT 返回值类型 JNICALL Java_包名_类名_函数名(JNIEnv * env, jobject obj)

缺点:

1、函数名比较长

2、写死了包名+类名,不够灵活

3、运行期才会匹配jni函数,性能低于动态注册

NDK动态注册

动态注册时机

在JNI中,有两个函数,分别是JNI_OnLoad()和JNI_OnUnload(),分别在加载库和卸载库的时候调用,定义在头文件jni.h

JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved);
JNIEXPORT void JNI_OnUnload(JavaVM* vm, void* reserved);

动态注册代码一般分为两步步

  • 使用JavaVM对象获取JNIEnv
  • 使用JNIEnv的RegisterNatives方法来注册函数

示例如下

java代码

public class T {

    public native static void staticRegisterCall();

    public native static int staticRegisterCall(String msg);
}

C代码

const char *class_name = "com/example/myapplication/T";

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
    LOGD("JNI_OnLoad");
    JNIEnv *env = NULL;

    if (jvm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
        return -1;
    }

    jclass t_class = env->FindClass(class_name);

    //函数指针使用函数名,括号不能丢掉
    JNINativeMethod methods[] = {
            {"staticRegisterCall", "()V",                   (void *) (dynamicMethod01)},
            {"staticRegisterCall", "(Ljava/lang/String;)I", (int *) (dynamicMethod02)}
    };

    env->RegisterNatives(t_class,
                         methods,
                         sizeof(methods) / sizeof(JNINativeMethod));

    return JNI_VERSION_1_6;
}

JNIEXPORT void JNI_OnUnload(JavaVM *vm, void *reserved) {
    LOGD("JNI_OnUnload");
}

env->RegisterNatives方法说明

// clazz	代表需要被注册的类
// methods	代表java方法与native方法的对应关系
// nMethods	代表前面methods参数的个数
jint RegisterNatives(jclass clazz, const JNINativeMethod* methods,jint nMethods)

JNINativeMethod说明

typedef struct {
    const char* name;		//java函数的名字
    const char* signature;	//java函数的签名
    void*       fnPtr;		//native函数指针
} JNINativeMethod;

native方法定义说明

如果native方法不需要JNIEnv、jclass/jobject,那么也可以直接不写。如下所示

// 也OK  如果你用不到  JNIEnv jobject ,可以不用写
void dynamicMethod01() { 
    LOGD("我是动态注册的函数 dynamicMethod01...");
}

int dynamicMethod02(JNIEnv *env, jclass thiz, jstring valueStr) { // 也OK
    const char *text = env->GetStringUTFChars(valueStr, nullptr);
    LOGD("我是动态注册的函数 dynamicMethod02... %s", text);
    env->ReleaseStringUTFChars(valueStr, text);
    return 200;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值