android jni 异常处理

说明:jni中没有try...catch...  throw  等方法来处理异常,引发的异常的env对象不处理,会继续运行至下一个env对象之前。此时需要通过env来处理异常。分为三种,直接清除,抛给java,程序退出,代码如下:(结合动态注册的文章食用)

#include <jni.h>
#include <string>
#include <android/log.h>

//
// Created by 15155 on 2022/11/23.
//

#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, "yuanrenxue->", __VA_ARGS__)


extern "C" JNIEXPORT jstring JNICALL
Java_com_yuanrenxue_course6_14_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

extern "C"
JNIEXPORT void JNICALL
Java_com_yuanrenxue_course6_14_MainActivity_demo(JNIEnv *env, jobject thiz) {
    // TODO: implement demo()

    __android_log_print((int) 6, "yuanrenxue->", "run here.");
    __android_log_print((int) 6, "yuanrenxue->", "current jni version %d", env->GetVersion());
//    jint version = env->GetVersion(); 获取JNI 版本
//    JNI_VERSION_1_6;
    //#define JNI_VERSION_1_1 0x00010001
    //#define JNI_VERSION_1_2 0x00010002
    //#define JNI_VERSION_1_4 0x00010004
    //#define JNI_VERSION_1_6 0x00010006
    //类操作
    //1.获取对象Class jcalss  com.yuanrenxue.course6_4  MysteryBox
    jclass mysteryBoxClass = env->FindClass("com/yuanrenxue/course6_4/MysteryBox");
    jclass clsClazz = env->GetObjectClass(mysteryBoxClass);
    jmethodID jmethodId = env->GetMethodID(clsClazz, "getSimpleName", "()Ljava/lang/String;");
    auto className = (jstring) env->CallObjectMethod(mysteryBoxClass, jmethodId);
    const char *str = env->GetStringUTFChars(className, nullptr);
    LOGD("获取对象  MysteryBox_Class_Name == %s", str);
    // 2.获取一个类的父类
    jclass parentClass = env->GetSuperclass(mysteryBoxClass);
    clsClazz = env->GetObjectClass(parentClass);
    jmethodId = env->GetMethodID(clsClazz, "getSimpleName", "()Ljava/lang/String;");
    className = (jstring) env->CallObjectMethod(parentClass, jmethodId);
    str = env->GetStringUTFChars(className, nullptr);
    LOGD("获取一个类的父类  MysteryBox_Parent_Class_Name == %s",str);
    //3.判断类型1是否可以安全的转换为类型2
    jboolean IsAssignableFrom = env->IsAssignableFrom(mysteryBoxClass, parentClass);
    LOGD("判断类型1是否可以安全的转换为类型2  mysteryBoxClass IsAssignableFrom parentClass== %d", IsAssignableFrom);

    //对象操作
    //1.不通过构造函数生成对象
    jobject mysteryBoxCObject = env->AllocObject(mysteryBoxClass);
    jmethodID toString_methodID = env->GetMethodID(mysteryBoxClass, "toString",
                                                   "()Ljava/lang/String;");
    auto mysteryBoxCObject_toString_methodID = (jstring) env->CallObjectMethod(mysteryBoxCObject,
                                                                               toString_methodID);
    str = env->GetStringUTFChars(mysteryBoxCObject_toString_methodID, nullptr);
    LOGD("不通过构造函数生成对象  mysteryBoxCObject_toString_methodID== %s", str);

    //2.通过构造函数生成对象
    jmethodID initMethod = env->GetMethodID(mysteryBoxClass, "<init>", "()V");
    jobject MysteryObject2 = env->NewObject(mysteryBoxClass, initMethod);
    toString_methodID = env->GetMethodID(mysteryBoxClass, "toString",
                                         "()Ljava/lang/String;");
    auto MysteryObject2_toString_methodID = (jstring) env->CallObjectMethod(
            MysteryObject2,
            toString_methodID);
    str = env->GetStringUTFChars(MysteryObject2_toString_methodID, nullptr);
    LOGD("通过构造函数生成对象  mysteryBoxClass, <init>, ()V== %s", str);
    //3.根据对象获取对应的类
    mysteryBoxClass = env->GetObjectClass(mysteryBoxCObject);
    clsClazz = env->GetObjectClass(mysteryBoxClass);
    jmethodId = env->GetMethodID(clsClazz, "getSimpleName", "()Ljava/lang/String;");
    className = (jstring) env->CallObjectMethod(mysteryBoxClass, jmethodId);
    str = env->GetStringUTFChars(className, nullptr);
    LOGD("根据对象获取对应的类  MysteryBox_Class_Name == %s", str);
    //4.判断某个对象是否为特定的实例
    jboolean IsInstanceOf = env->IsInstanceOf(mysteryBoxCObject, mysteryBoxClass);
    LOGD("判断某个对象是否为特定的实例 IsInstanceOf == %hhu",IsInstanceOf);

    //属性操作
    //1.获取非静态成员属性的ID mysteryBoxCObject price
    jfieldID price_filed_id = env->GetFieldID(mysteryBoxClass, "price", "I");
    //2.获取非静态成员属性的值(方法的合集)
    jint price = env->GetIntField(MysteryObject2, price_filed_id);
    LOGD("获取非静态成员属性的值 price == %d",price);
    //3.设置非静态成员属性的值(方法的合集)
    env->SetIntField(MysteryObject2, price_filed_id, 20);
    price = env->GetIntField(MysteryObject2, price_filed_id);
    LOGD("设置非静态成员属性的值 price == %d",price);
    //4.获取静态成员属性的ID MysteryBox  BASE_PRICE
    jfieldID BASE_PRICE_filed_id = env->GetStaticFieldID(mysteryBoxClass, "BASE_PRICE", "I");
    //5.获取静态成员属性的值
    jint static_price = env->GetStaticIntField(mysteryBoxClass, BASE_PRICE_filed_id);
    LOGD("获取静态成员属性的值  BASE_PRICE == %d",static_price);
    //6.设置静态成员属性的值
    env->SetStaticIntField(mysteryBoxClass, BASE_PRICE_filed_id, 666);
    static_price = env->GetStaticIntField(mysteryBoxClass, BASE_PRICE_filed_id);
    LOGD("设置静态成员属性的值 BASE_PRICE == %d",static_price);

    //方法的操作  getContent
    //1.获取非静态方法id
    jmethodID getContentmethid = env->GetMethodID(mysteryBoxClass, "getContent",
                                                  "()Ljava/lang/String;");
    //2.调用非静态方法
    auto getContent = (jstring) env->CallObjectMethod(MysteryObject2, getContentmethid);
    str = env->GetStringUTFChars(getContent, nullptr);
    LOGD("调用非静态方法 getContent == %s",str);
    //3.获取静态方法id  staticMethod
    jmethodID staticMethodID = env->GetStaticMethodID(mysteryBoxClass, "staticMethod",
                                                      "(Ljava/lang/String;I)Ljava/lang/String;");
    //4.调用静态方法
    jstring jstring1 = env->NewStringUTF("hell word!");
    auto callstatic = (jstring) env->CallStaticObjectMethod(mysteryBoxClass, staticMethodID,
                                                            jstring1, 30);
    str = env->GetStringUTFChars(callstatic, nullptr);
    LOGD("调用静态方法 callstatic == %s", str);

/*
 * 2022-12-06 01:34:45.102 6536-6536/com.yuanrenxue.course6 D/yuanrenxue->: onCreate: run sucess!!
2022-12-06 01:34:45.103 6536-6536/com.yuanrenxue.course6 E/yuanrenxue->: run here.
2022-12-06 01:34:45.103 6536-6536/com.yuanrenxue.course6 E/yuanrenxue->: current jni version 65542
2022-12-06 01:34:45.103 6536-6536/com.yuanrenxue.course6 E/yuanrenxue->: 获取对象  MysteryBox_Class_Name == MysteryBox
2022-12-06 01:34:45.103 6536-6536/com.yuanrenxue.course6 E/yuanrenxue->: 获取一个类的父类  MysteryBox_Parent_Class_Name == MysteryParentBox
2022-12-06 01:34:45.103 6536-6536/com.yuanrenxue.course6 E/yuanrenxue->: 判断类型1是否可以安全的转换为类型2  mysteryBoxClass IsAssignableFrom parentClass== 1
2022-12-06 01:34:45.103 6536-6536/com.yuanrenxue.course6 E/yuanrenxue->: 不通过构造函数生成对象  mysteryBoxCObject_toString_methodID== MysteryBox{content='null', isOpened=false, price=0, brand='null'}
2022-12-06 01:34:45.103 6536-6536/com.yuanrenxue.course6 E/yuanrenxue->: 通过构造函数生成对象  mysteryBoxClass, <init>, ()V== MysteryBox{content='普通款', isOpened=false, price=10, brand='手办盲盒'}
2022-12-06 01:34:45.104 6536-6536/com.yuanrenxue.course6 E/yuanrenxue->: 根据对象获取对应的类  MysteryBox_Class_Name == MysteryBox
2022-12-06 01:34:45.104 6536-6536/com.yuanrenxue.course6 E/yuanrenxue->: 判断某个对象是否为特定的实例 IsInstanceOf == 1
2022-12-06 01:34:45.104 6536-6536/com.yuanrenxue.course6 E/yuanrenxue->: 获取非静态成员属性的值 price == 10
2022-12-06 01:34:45.104 6536-6536/com.yuanrenxue.course6 E/yuanrenxue->: 设置非静态成员属性的值 price == 20
2022-12-06 01:34:45.104 6536-6536/com.yuanrenxue.course6 E/yuanrenxue->: 获取静态成员属性的值  BASE_PRICE == 10
2022-12-06 01:34:45.104 6536-6536/com.yuanrenxue.course6 E/yuanrenxue->: 设置静态成员属性的值 BASE_PRICE == 666
2022-12-06 01:34:45.104 6536-6536/com.yuanrenxue.course6 E/yuanrenxue->: 调用非静态方法 getContent == 这个盲盒没有打开哦
2022-12-06 01:34:45.104 6536-6536/com.yuanrenxue.course6 D/yuanrenxue->: staticMethod: name=hell word!, price=30
2022-12-06 01:34:45.104 6536-6536/com.yuanrenxue.course6 E/yuanrenxue->: 调用静态方法 callstatic == 我是静态方法变量
 */
}


void OnCreate(JNIEnv *env, jobject thiz, jobject savedInstanceState) {
    //super.onCreate(savedInstanceState);
    jclass MainActivity_cls1 = env->GetObjectClass(thiz);
    jclass AppCompatActivity = env->GetSuperclass(MainActivity_cls1);
    jmethodID onCreate = env->GetMethodID(AppCompatActivity, "onCreate", "(Landroid/os/Bundle;)V");
    env->CallNonvirtualVoidMethod(thiz, AppCompatActivity,  onCreate, savedInstanceState);
    LOGD("super.onCreate(savedInstanceState);被调用");
    //setContentView(R.layout.activity_main);
    jmethodID setContentView_mid = env->GetMethodID(MainActivity_cls1, "setContentView", "(I)V");
    char *R_layout = "com/yuanrenxue/course6_4/R$layout";
    jclass layout = env->FindClass(R_layout);
    jfieldID activity_main_fid = env->GetStaticFieldID(layout, "activity_main", "I");
    jint activity_main = env->GetStaticIntField(layout, activity_main_fid);
    env->CallVoidMethod(thiz, setContentView_mid, activity_main);
    LOGD("setContentView(R.layout.activity_main);  被调用");

//    //第一行:super.onCreate(savedInstanceState);因此首先需要获取superclass
//    jclass AppCompatActivity_cls1 = env->FindClass(
//            "androidx/appcompat/app/AppCompatActivity");//已经知道类名
//    jclass MainActivity_cls1 = env->FindClass("com/yuanrenxue/course6_4/MainActivity");
////调用这个函数protected void onCreate(@Nullable Bundle savedInstanceState)
//    jmethodID superclassOnCreate_mid = env->GetMethodID(AppCompatActivity_cls1, "onCreate",
//                                                        "(Landroid/os/Bundle;)V");
//    env->CallNonvirtualVoidMethod(thiz, AppCompatActivity_cls1, superclassOnCreate_mid,
//                                  savedInstanceState);
//
////第二行:setContentView(R.layout.activity_main);
//    jmethodID setContentView_mid = env->GetMethodID(MainActivity_cls1, "setContentView", "(I)V");
//    char *R_layout = "com/yuanrenxue/course6_4/R$layout";
//    jclass R_layout_cls = env->FindClass(R_layout);
//    jfieldID activity_main_fid = env->GetStaticFieldID(R_layout_cls, "activity_main",
//                                                       "I");//这里对应R$layout那个图看出来的


    jint activity_main_value = env->GetStaticIntField(MainActivity_cls1, activity_main_fid);
    env->CallVoidMethod(thiz, setContentView_mid, activity_main_value);
    // private native String demoUTFString();
    jmethodID demoUTFString = env->GetMethodID(MainActivity_cls1, "demoUTFString",
                                               "()Ljava/lang/String;");
    auto str = (jstring) env->CallObjectMethod(thiz, demoUTFString);
    LOGD("private native String demoUTFString(); 被调用");
//    Log.d(TAG, "onCreate: demoUTFString = " + this.demoUTFString());
    jclass Log = env->FindClass("android/util/Log");
    jmethodID d = env->GetStaticMethodID(Log, "d", "(Ljava/lang/String;Ljava/lang/String;)I");
    jfieldID TAG_ID = env->GetStaticFieldID(MainActivity_cls1, "TAG", "Ljava/lang/String;");
    jstring tag = static_cast<jstring>(env->GetStaticObjectField(MainActivity_cls1, TAG_ID));
    env->CallStaticIntMethod(Log, d, tag, str);
    LOGD("Log.d(TAG, \"onCreate: demoUTFString = \" + this.demoUTFString()); 被调用");
    jmethodID exceptionMId = env->GetMethodID(MainActivity_cls1,"exception", "()V");
    env->CallVoidMethod(thiz,exceptionMId);
    LOGD("private native void exception();  被调用");
}


jint JNI_OnLoad(JavaVM *vm, void *reserved) {
    __android_log_print(6, "yuanrenxue->", "JNI_OnLoad函数被调用");
    JNIEnv *env = nullptr;
    if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6) != JNI_OK) {
        return JNI_ERR;
    }
    //动态注册
    // com.yuanrenxue.course6_4
    jclass classzz = env->FindClass("com/yuanrenxue/course6_4/MainActivity");
    /*
     * jint RegisterNatives(jclass clazz, const JNINativeMethod* methods,
        jint nMethods)
     */
    /*
     * typedef struct {
    const char* name;
    const char* signature;
    void*       fnPtr;
} JNINativeMethod;
     */
    JNINativeMethod methods[] = {
            {"onCreate", "(Landroid/os/Bundle;)V", (void *) OnCreate}
    };
    env->RegisterNatives(classzz, methods, 1);
    return JNI_VERSION_1_6;
}
////同时静态注册 和 同时动态注册 会使用动态注册的


extern "C"
JNIEXPORT void JNICALL
Java_com_yuanrenxue_course6_14_MainActivity_exception(JNIEnv *env, jobject thiz) {
    // TODO: implement exception()
    jclass clazz = env->GetObjectClass(thiz);
    env->GetStaticFieldID(clazz, "test1", "Ljava/lang/String;");
    //1.在nativate处理异常 不抛给java
    jthrowable jthrowable1 = env->ExceptionOccurred();
    if (jthrowable1) {
        //进入这里表示出现了异常 小根据需求进行异常的处理
        LOGD("在nativate处理异常 不抛给java");
        env->ExceptionClear();//清除掉当前的异常,防止程序崩溃
        env->GetStaticFieldID(clazz, "test", "Ljava/lang/String;");
    }
    LOGD("在nativate处理异常 不抛给java");
    //2.把异常抛给java
    env->GetStaticFieldID(clazz, "test1", "Ljava/lang/String;");
    if (jthrowable1) {
        //进入这里表示出现了异常 小根据需求进行异常的处理
        LOGD("把异常抛给java");
        env->ExceptionDescribe();
        env->ExceptionClear();//清除掉当前的异常,防止程序崩溃
        env->GetStaticFieldID(clazz, "test", "Ljava/lang/String;");
//        env->ThrowNew(env->FindClass("java/lang/Exception"),"nativate 把异常抛给java");
        env->DeleteLocalRef(clazz); //释放资源
    }
    //3.抛出致命异常 程序退
    env->FatalError("抛出致命异常 程序退出");
}

  

posted @ 2022-12-08 03:17  山水无期  阅读(151)  评论(0编辑  收藏  举报