美文网首页
jni-05、排序、静态和非静态缓存、异常、模拟JNIEnv

jni-05、排序、静态和非静态缓存、异常、模拟JNIEnv

作者: 喂_balabala | 来源:发表于2022-09-05 19:21 被阅读0次

    排序

    Java
    // public native void sort(int[] arr);
    external fun sort(arr: IntArray)
    
    // static { System.loadLibrary("native-lib"); }
    companion object {
        init {
            System.loadLibrary("native-lib")
        }
    }
    
    // 点击事件
    fun sortAction(view: View) {
        val arr = intArrayOf(11, 22, -3, 2, 4, 6, -15)
        sort(arr)
        for (element in arr) {
            Log.e("eeeee", "sortAction: " + element.toString() + "\t")
        }
    }
    
    native
    // 比较函数了
    int compare(const jint * number1, const jint * number2) {
        return *number1 - *number2;
    }
    
    extern "C"
    JNIEXPORT void JNICALL
    Java_com_derry_as_1jni_1project_MainActivity_sort(JNIEnv *env, jobject thiz, jintArray arr) {
        // 对 arr排序  内置的函数
        jint * intArray = env->GetIntArrayElements(arr, nullptr);
    
        int length = env->GetArrayLength(arr);
    
        // NDK 很大的工具链(Java JNI,C++,stdlib ....) 工具箱
    
        /**
         * 参数1:void * 数组的首地址
         * 参数2:数组的大小长度
         * 参数3:元素的大小
         * 参数4:对比的方法指针
         */
        qsort(intArray, length, sizeof(int),
              reinterpret_cast<int (*)(const void *, const void *)>(compare));
    
        env->ReleaseIntArrayElements(arr, intArray, 0); // 0 操纵杆 更新KT的数组
    }
    

    非静态缓存(普通缓存)

    • Java
    static {
        System.loadLibrary("native-lib");
    }
    
    // 假设这里定义了一堆变量
    static String name1  ="T1";
    static String name2  ="T2";
    static String name3  ="T3";
    static String name4  ="T4";
    static String name5  ="T5";
    static String name6  ="T6";
    public static native void localCache(String name); // 普通的局部缓存,弊端演示
    //点击事件
    public void staticCacheAction(View view) {
            localCache("AAAA");
    }
    
    • native
    extern "C"
    JNIEXPORT void JNICALL
    Java_com_derry_as_1jni_1project_MainActivity2_localCache(JNIEnv *env, jclass clazz, jstring name) {
    
        // 非静态缓存
    
        jfieldID f_id = nullptr;
    
        if (f_id == nullptr) {
            f_id = env->GetStaticFieldID(clazz, "name1", "Ljava/lang/String;"); // 有点耗费性能
        } else  {
            LOGE("空的");
        }
    
        env->SetStaticObjectField(clazz, f_id, name); // 修改 AAA
    
        f_id = nullptr;
    }
    

    静态缓存

    • Java
    // 假设这里定义了一堆变量
    static String name1  ="T1";
    static String name2  ="T2";
    static String name3  ="T3";
    static String name4  ="T4";
    static String name5  ="T5";
    static String name6  ="T6";
    public static native void initStaticCache(); // 初始化静态缓存
    public static native void staticCache(String name);
    public static native void clearStaticCache(); // 清除化静态缓存
    
    // 点击事件
    public void staticCacheAction(View view) {
    
        // 初始化静态缓存
        initStaticCache(); // 如果是在类里面, Person Student ,必须在类的构造函数初始化
    
        staticCache("BBB");
        staticCache("BBB");
        staticCache("BBB");
        staticCache("BBB");
        staticCache("BBB");
        staticCache("BBB");
        staticCache("BBB");
    }
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
        clearStaticCache(); // 清除化静态缓存
    }
    
    • native
    // 像OpenCV,WebRTC,等等 大量使用 静态缓存 ..
    
    static jfieldID f_name1_id = nullptr;
    static jfieldID f_name2_id = nullptr;
    static jfieldID f_name3_id = nullptr;
    static jfieldID f_name4_id = nullptr;
    static jfieldID f_name5_id = nullptr;
    static jfieldID f_name6_id = nullptr;
    
    // 先缓存
    extern "C"
    JNIEXPORT void JNICALL
    Java_com_derry_as_1jni_1project_MainActivity2_initStaticCache(JNIEnv *env, jclass clazz) {
        f_name1_id = env->GetStaticFieldID(clazz, "name1", "Ljava/lang/String;");
        f_name2_id = env->GetStaticFieldID(clazz, "name2", "Ljava/lang/String;");
        f_name3_id = env->GetStaticFieldID(clazz, "name3", "Ljava/lang/String;");
        f_name4_id = env->GetStaticFieldID(clazz, "name4", "Ljava/lang/String;");
        f_name5_id = env->GetStaticFieldID(clazz, "name5", "Ljava/lang/String;");
        f_name6_id = env->GetStaticFieldID(clazz, "name6", "Ljava/lang/String;");
    }
    
    // 使用
    extern "C"
    JNIEXPORT void JNICALL
    Java_com_derry_as_1jni_1project_MainActivity2_staticCache(JNIEnv *env, jclass clazz, jstring name) {
        // 不会反复 GetStaticFieldID 提供性能
        env->SetStaticObjectField(clazz, f_name1_id, name);
        env->SetStaticObjectField(clazz, f_name2_id, name);
        env->SetStaticObjectField(clazz, f_name3_id, name);
        env->SetStaticObjectField(clazz, f_name4_id, name);
        env->SetStaticObjectField(clazz, f_name5_id, name);
        env->SetStaticObjectField(clazz, f_name6_id, name);
    }
    
    // 清除
    extern "C"
    JNIEXPORT void JNICALL
    Java_com_derry_as_1jni_1project_MainActivity2_clearStaticCache(JNIEnv *env, jclass clazz) {
        f_name1_id = nullptr;
        f_name2_id = nullptr;
        f_name3_id = nullptr;
        f_name4_id = nullptr;
        f_name5_id = nullptr;
        f_name6_id = nullptr;
    }
    

    异常处理

    • Java
    public class MainActivity3 extends AppCompatActivity {
        static {
            System.loadLibrary("native-lib");
        }
    
        static String name1 = "T1";
    
        // 下面是异常处理
        public static native void exception();
        public static native void exception2() throws NoSuchFieldException; // NoSuchFieldException接收C++层抛上来的异常
        public static native void exception3();
    
        public static native String derryAction();
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
        }
    
        public void exceptionAction(View view) {
            exception(); // C++层自己做了补救措施了
    
            // 捕获人家C++层抛上来的异常
            try {
                exception2();
            } catch (NoSuchFieldException exception) {
                exception.printStackTrace();
                Log.d("Derry", "exceptionAction: 异常被我捕获了");
            }
    
            exception3();
    
            String result = derryAction();
        }
    
        // 专门给 C++(native层) 层调用的 函数
        public static void show() throws Exception {
            Log.d("eeee", "show: 1111");
            Log.d("eeee", "show: 1111");
            Log.d("eeee", "show: 1111");
            Log.d("eeee", "show: 1111");
            Log.d("eeee", "show: 1111");
            Log.d("eeee", "show: 1111");
    
            throw new NullPointerException("我是Java中抛出的异常,我的show方法里面发送了Java逻辑错误");
        }
    }
    
    
    • native
    // 异常1  【native层主动干的异常】
    extern "C"
    JNIEXPORT void JNICALL
    Java_com_derry_as_1jni_1project_MainActivity3_exception(JNIEnv *env, jclass clazz) {
        // 假设现在想操作 name999 ,没有name999就会在native层奔溃掉
        jfieldID f_id = env->GetStaticFieldID(clazz, "name999", "Ljava/lang/String;");
    
        // 奔溃后,有两种解决方案
    
        // 方式1 补救措施
    
        jthrowable thr =  env->ExceptionOccurred(); // 监测本次执行,到底有没有异常   JNI函数里面代码有问题
    
        if(thr) { // 非0 进去,监测到有异常
            LOGD("C++层有异常 监测到了");
    
            env->ExceptionClear(); // 此异常被清除
    
            // 开始 补救措施
            jfieldID f_id = env->GetStaticFieldID(clazz, "name1", "Ljava/lang/String;");
        }
    
    
    }
    
    // 异常2 【native层主动干的异常】
    extern "C"
    JNIEXPORT void JNICALL
    Java_com_derry_as_1jni_1project_MainActivity3_exception2(JNIEnv *env, jclass clazz) {
        // 假设现在想操作 name999 ,没有name999就会在native层奔溃掉
        jfieldID f_id = env->GetStaticFieldID(clazz, "name8888", "Ljava/lang/String;");
    
        // 奔溃后,有两种解决方案
    
        // 方式2 往Java层抛
    
        jthrowable jthrowable = env->ExceptionOccurred(); // 监测本次执行,到底有没有异常   JNI函数里面代码有问题
    
        if(jthrowable) { // 非0 进去,监测到有异常
            LOGD("C++层有异常 监测到了");
    
            env->ExceptionClear(); // 此异常被清除
    
            // Throw抛一个 Java的对象     java/lang/String    java/xxxxx/xxx/NullExxx
            jclass clz = env->FindClass("java/lang/NoSuchFieldException");
            env->ThrowNew(clz, "NoSuchFieldException 是在是找不到 name8888啊,没有办法,抛给你了");
        }
    }
    
    // 异常3 【native层被动干的异常  被动 我是Java方法坑了】
    extern "C"
    JNIEXPORT void JNICALL
    Java_com_derry_as_1jni_1project_MainActivity3_exception3(JNIEnv *env, jclass clazz) {
        jmethodID showID = env->GetStaticMethodID(clazz, "show", "()V");
        env->CallStaticVoidMethod(clazz, showID); // 是不是这句话奔溃的   1是   2不是   答:不是,只是他引起的而已
    
        // ExceptionCheck 《==》 慢慢的奔溃的,相当于给了你空余时间,既然不是马上奔溃,我就可以检测
    
        // JNI函数里面代码有问题 没有问题,给你空余时间,慢慢的奔溃的
        if (env->ExceptionCheck()) {
            env->ExceptionDescribe(); // 输出描述 信息
            env->ExceptionClear(); // 此异常被清除    业务逻辑控制
        }
    
        // 注意实现:
        /*// 奔溃后,下面的语句,照样打印
        LOGI("C++层>>>>>>>>>>>>>>>>>>>>>>>>>>>>1");
        LOGI("C++层>>>>>>>>>>>>>>>>>>>>>>>>>>>>2");
        LOGI("C++层>>>>>>>>>>>>>>>>>>>>>>>>>>>>3");
        LOGI("C++层>>>>>>>>>>>>>>>>>>>>>>>>>>>>4");
        LOGI("C++层>>>>>>>>>>>>>>>>>>>>>>>>>>>>5");
    
        env->NewStringUTF("AAAA"); // 局部引用 奔溃给磨平*/
    }
    

    C++异常

    #include <iostream>
    #include <string>
    using namespace std;
    
    void exceptionMethod01() {
        throw "我报废了"; // const char *
    }
    
    class Student {
    public:
        char * getInfo() {
            return "自定义";
        }
    };
    
    void exceptionMethod02() {
        Student student;
        throw student;
    }
    
    int main() {
        try {
            exceptionMethod01();
        } catch ( const char * & msg) {
            cout << "捕获到异常1:" << msg << endl;
        }
    
        try {
            exceptionMethod02();
        } catch (Student & msg) {
            cout << "捕获到异常2:" << msg.getInfo() << endl;
        }
        return 0;
    }
    
    

    模拟JNIEnv

    // JNI 怎么学习?
    //    1.JNIEnv 300个函数  常用的函数就行了
    //    2.手写JNIEnv
    
    #include <iostream>
    #include <string>
    using namespace std;
    
    // 模拟 jstring
    typedef char * jstring;
    
    // 模拟 jobject
    typedef char * jobject;
    
    // 如果是C语言  C++也是会调用C的 JNINativeInterface
    typedef const struct JNINativeInterface * JNIEnv; // 定义了一个结构体指针的别名   一级指针
    
    struct JNINativeInterface {
        // 300多个 函数指针 声明 -------  指针函数对应的实现 我们现在看不到 在库
        // ...
        jstring (*NewStringUTF) (JNIEnv *, char *); // 函数指针 声明
    };
    
    // 指针函数对应的实现 我们现在看不到 在库
    jstring NewStringUTF(JNIEnv * env, char * str) {
        // 注意:在真正的源码中,这里需要很多复杂的代码来转换 (毕竟涉及到跨越语言操作了), 我们就简写了
        // char * str <---> jstring str
        return str;
    }
    
    jstring Java_com_derry_as_1jni_1project_MainActivity3_derryAction(JNIEnv *env, jobject job) {
        // env 已经是二级指针了
        return (*env)->NewStringUTF(env, "9527"); // 函数指针 不起作用
    }
    
    // 模拟 紫色区域  内部处理的逻辑 我们看不到
    int main() {
        // 构建 JNIEnv *
        struct JNINativeInterface nativeInterface;
    
        // 把结构体函数指针 进行赋值  (函数指针---实现)
        nativeInterface.NewStringUTF = NewStringUTF;
    
        // 处理生成好的 JNIEnv * 后,传递给 JNI函数
        JNIEnv env = &nativeInterface;  // 本来就是 一级指针
        JNIEnv * jniEnv = &env; // 二级指针
    
        jstring result = Java_com_derry_as_1jni_1project_MainActivity3_derryAction(jniEnv, "com/derry/jni/MainActivity");
    
        // 把jstring 转换 给 Java String 简化了
        // jstring ----->  String
        printf("Java层拿到 C++给我们的 String result:%s", result);
    }
    
    

    总结

    • native崩溃后会有一点反应时间可以执行后面的代码,但不能创建局部引用

    相关文章

      网友评论

          本文标题:jni-05、排序、静态和非静态缓存、异常、模拟JNIEnv

          本文链接:https://www.haomeiwen.com/subject/kmrbnrtx.html