JNI 中的异常处理

一般会有两种异常

  1. Native 层代码出现的异常.
  2. Native 层调用 Java 层代码时, Java 层出现异常

第一种又分为两种解决方案, 分别是在 Native 层自己处理, 进行补救. 或者是将异常抛出到 Java 层, 由Java 层进行处理.

下面先是第一种方式的处理, 包含了两种解决方案.
Java 层代码, 这里是使用 Kotlin 写的


        binding.sampleText.setOnClickListener{
            //方式1, 在 Native 层进行处理
            exceptionFromJNI1()
            //执行完JNI 后, Toast一下值
            Toast.makeText(this, name1, Toast.LENGTH_SHORT).show()

            //方式2, 在 Native 层进行抛出, java 层处理
            try {
                exceptionFromJNI2()
            }catch (e:NoSuchFieldException){
                e.printStackTrace()
                Log.e("Error", "---------------------异常捕获-----")
            }

//            exceptionFromJNI3()
        }

Native 代码

extern "C"
JNIEXPORT void JNICALL Java_com_aaatest_study003_MainActivity_exceptionFromJNI1(JNIEnv *env, jobject thiz) {
    //故意制造异常
    jclass pJclass = env->GetObjectClass(thiz);

    jfieldID f_id = env->GetFieldID(pJclass, "name999", "Ljava/lang/String;");

    //检测本次执行有没有异常
    jthrowable occurred = env->ExceptionOccurred();
    if(occurred) { //非0, 表示有异常
        _MY_LOGE("C++层中出现了异常");
        env->ExceptionClear();  //清除异常
        //尝试补救
        jfieldID f_id = env->GetFieldID(pJclass, "name1", "Ljava/lang/String;");
        //获取值
        jstring jstr = (jstring) env->GetObjectField(thiz, f_id);
        const char * c_str = env->GetStringUTFChars(jstr, nullptr);
        //修改值
        char new_char[40] = "name1 = ";
        strcat(new_char, c_str);
        //将 c 字符串转为 jni 字符串
        jstring str_jni_new = env->NewStringUTF(new_char);
        env->SetObjectField(thiz, f_id, str_jni_new);
        //释放
        env->ReleaseStringUTFChars(jstr, c_str);

        _MY_LOGE("开始补救, 值为:%s",new_char);
    }
}



extern "C"
JNIEXPORT void JNICALL Java_com_aaatest_study003_MainActivity_exceptionFromJNI2(JNIEnv *env, jobject thiz) {
    //故意制造异常
    jclass pJclass = env->GetObjectClass(thiz);

    jfieldID f_id = env->GetFieldID(pJclass, "name999", "Ljava/lang/String;");

    jthrowable occurred = env->ExceptionOccurred();

    if(occurred) {
        //先清除异常,
        env->ExceptionClear();
        //抛出
        jclass exceptionClz = env->FindClass("java/lang/NoSuchFieldException");
        env->ThrowNew(exceptionClz, "没有找到字段 name888");
    }

}

接着是第二种异常处理的解决方案, 主要是由 Native 调用 java 方法时出现异常.
Java 代码

    //写给C++调用的函数, 在java 层制造异常
    public fun show(){
        throw NullPointerException()
        Log.e("Error", "---------------------java 层 show 方法抛出异常-----")
    }

Native 代码

extern "C"
JNIEXPORT void JNICALL Java_com_aaatest_study003_MainActivity_exceptionFromJNI3(JNIEnv *env, jobject thiz) {
    //被动处理异常, JNI 代码没有问题. java 代码有问题.
    jclass objectClass = env->GetObjectClass(thiz);
    jmethodID methodId = env->GetMethodID(objectClass, "show", "()V");
    env->CallVoidMethod(thiz, methodId);
    //在怀疑java会有问题的地方, 紧跟以下代码. 不要在中间插入其他代码.
    if(env->ExceptionCheck()) {
        env->ExceptionDescribe(); //输出异常信息
        env->ExceptionClear();
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章