美文网首页
NDK基础(二)——数组、全局变量、RegisterNative

NDK基础(二)——数组、全局变量、RegisterNative

作者: 王志强_9380 | 来源:发表于2020-06-29 15:14 被阅读0次

    数组

    整形数组
    extern "C"
    JNIEXPORT jintArray JNICALL
    Java_com_example_ffmpegapplication_NativeStudy_ArrayTest(JNIEnv *env, jclass type,
                                                             jintArray array_) {
        jintArray pArray = env->NewIntArray(10);
    
        jsize length = env->GetArrayLength(array_);
        // TODO 修改数组
        jint *array = env->GetIntArrayElements(array_, NULL);
        for (int i = 0; i < length; i++) {
            array[i] = array[i] + 1;
        }
        env->ReleaseIntArrayElements(array_, array, 0);
    
    
        jint nativeArray[length];
        env->GetIntArrayRegion(array_, 0, length, nativeArray);
        nativeArray[0] = 0;
        nativeArray[1] = 9999;
        nativeArray[2] = 8888;
        env->SetIntArrayRegion(array_, 1, 3, nativeArray);
    
        return array_;
    }
    

    打印:

    01-19 16:34:29.810: E/www(22129): ArrayTest: 100
    01-19 16:34:29.810: E/www(22129): ArrayTest: 0
    01-19 16:34:29.810: E/www(22129): ArrayTest: 9999
    01-19 16:34:29.810: E/www(22129): ArrayTest: 8888
    01-19 16:34:29.810: E/www(22129): ArrayTest: 7
    01-19 16:34:29.810: E/www(22129): ArrayTest: 8
    01-19 16:34:29.810: E/www(22129): ArrayTest: 9
    01-19 16:34:29.810: E/www(22129): ArrayTest: 10
    
    • Get<Type>ArrayElements:获得指向Java数组元素的直接指针
    • Release<Type>ArrayElements:释放指向Java数组元素的直接指针,最后一个参数是释放模式:
      0:将内容复制回Java并释放native数组
      JNI_COMMIT:将内容复制回Java但是不释放native数组,一般用于周期性的更新一个java数组
      JNI_ABORT:释放native数组但是不将内容复制回Java
    • Get<Type>ArrayRegion:将Java数组复制到给定的C数组中。当数组很大时,这样复制数组会引起性能问题
    • Set<Type>ArrayRegion:将C数组复制到Java数组
    object数组
    extern "C"
    JNIEXPORT jobjectArray JNICALL
    Java_com_example_ffmpegapplication_NativeStudy_StringArrayTest(JNIEnv *env, jclass type,
                                                                   jobjectArray array) {
        char *str1 = "Hello  ";
        // TODO 修改object数组
        jsize length = env->GetArrayLength(array);
        for (int i = 0; i < length; i++) {
            jstring pJobject = (jstring) env->GetObjectArrayElement(array, i);
            const char *string = env->GetStringUTFChars(pJobject, 0);
            char str3[20];
            strcpy(str3, str1);
            strcat(str3, string);
            jstring pJNewstring = env->NewStringUTF(str3);
            env->SetObjectArrayElement(array, i, pJNewstring);
            env->DeleteLocalRef(pJobject);
            env->DeleteLocalRef(pJNewstring);
        }
        return array;
    }
    

    调用:

    String[] array_string = {"java", "Android", "C", "C++"};
    StringArrayTest(array_string);
    for (int i = 0; i < array_string.length; i++) {
        Log.e("", "array_stringTest: " + array_string[i]);
    }
    

    打印:

    01-19 12:36:16.355: E/www(28743): array_stringTest: Hello  java
    01-19 12:36:16.355: E/www(28743): array_stringTest: Hello  Android
    01-19 12:36:16.355: E/www(28743): array_stringTest: Hello  C
    01-19 12:36:16.355: E/www(28743): array_stringTest: Hello  C++
    

    DeleteLocalRef:释放局部引用。在上面代码的for循环中,一直在创建局部引用对象,如果次数太多不去释放的话,就会造成局部引用泄露导致崩溃。

    也可以批量的释放局部引用

    // TODO 批量释放局部变量 通知JVM 您将使用超过 100 个本地引用。
    if (env->EnsureLocalCapacity(100) == 0) {    //确保至少给定数量的局部引用能在当前线程被创建。如果创建成功就返回0,否则就会返回一个负数
        env->PushLocalFrame(100);
        env->NewStringUTF(str1);
        env->NewStringUTF(str1);
        env->NewStringUTF(str1);
        env->NewStringUTF(str1);
        env->PopLocalFrame(NULL);
    }
    

    注意:

    • 方法体中的一切引用都是局部的,包括:方法的Object参数,FindClass,GetObjectClass,GetObjectFeild,GetObjectArrayElement,NewStringUTF,NewLocalRef等
    • native方法返回时,没有释放的局部引用会自动释放

    全局变量

    jclass mNativeStudyTest;
    jfieldID mBooleanfieldID;
    jfieldID mIntfieldID;
    jmethodID mPlayNativeStudyTestID;
    jmethodID mPlayNativeStudyTestStaticID;
    
    
    JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
        JNIEnv *env = NULL;
        if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6) != JNI_OK) {
            return JNI_ERR;
        }
        jclass pJclass = env->FindClass("com/example/ffmpegapplication/NativeStudyTest");
        mNativeStudyTest = static_cast<jclass>(env->NewGlobalRef(pJclass));
        mBooleanfieldID = env->GetFieldID(mNativeStudyTest, "mBooleanfield", "Z");
        mIntfieldID = env->GetStaticFieldID(mNativeStudyTest, "mIntfield", "I");
        mPlayNativeStudyTestID = env->GetMethodID(mNativeStudyTest, "playNativeStudyTest1", "()V");
        mPlayNativeStudyTestStaticID = env->GetStaticMethodID(mNativeStudyTest,
                                                              "playNativeStudyTestStatic", "()V");
       
        LOGE("%s","JNI_OnLoad end");
        return JNI_VERSION_1_6;
    }
    
    JNIEXPORT void JNI_OnUnload(JavaVM *vm, void *reserved) {
        JNIEnv *env = NULL;
        if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6) != JNI_OK) {
            return;
        }
        env->DeleteGlobalRef(mNativeStudyTest);
    }
    

    注意:

    • 如果是Object对象,需要使用NewGlobalRef来赋值给全局变量,直接用等号是错误的
    • 全局的Object对象需要使用DeleteGlobalRef释放
    • jfieldID 和 jmethodID 不是Object对象,可以直接使用等号赋值
    • JNI_OnLoad在java中使用System.loadLibrary时会调用,一般在这里面初始化,相对的是JNI_OnUnload

    RegisterNatives注册本地方法

    static jobject native_study_register_test1(JNIEnv *env, jobject thiz, jobject nativeStudyTest) {
        LOGE("%s","调用方法native_study_register_test1");
    
        jobject dpobj = env->AllocObject(mNativeStudyTest);
        return dpobj;
    }
    
    static void native_study_register_test2(JNIEnv *env, jobject thiz, jobject nativeStudyTest, jint intfield) {
        LOGE("%s","调用方法native_study_register_test2");
    }
    
    static void native_study_register_test3(JNIEnv *env, jobject thiz) {
        LOGE("%s","调用方法native_study_register_test3");
    }
    
    static void native_study_register_test4(JNIEnv *env, jobject thiz) {
        LOGE("%s","调用方法native_study_register_test4");
    }
    
    static JNINativeMethod methods[] = {
            {"test1",
                    "(Lcom/example/ffmpegapplication/NativeStudyTest;)Lcom/example/ffmpegapplication/NativeStudyTest;",
                    (void*)native_study_register_test1},
            {"test2",
                    "(Lcom/example/ffmpegapplication/NativeStudyTest;I)V",
                    (void*)native_study_register_test2},
            {"test3",
                    "()V",
                    (void*)native_study_register_test3},
            {"test4",
                    "()V",
                    (void*)native_study_register_test4}
    };
    #define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
    int register_method(JNIEnv *env) {
        char* classPathName = "com/example/ffmpegapplication/NativeStudy";
        jclass pJclass = env->FindClass(classPathName);
        LOGE("%s%d","register_method ", NELEM(methods));
        jint result = env->RegisterNatives(pJclass, methods, NELEM(methods));
        LOGE("%s","register_method end");
        return result;
    }
    

    java代码

    public native NativeStudyTest test1(NativeStudyTest nst);
    public native void test2(NativeStudyTest nst, int i);
    public native void test3();
    public native void test4();
    

    相关文章

      网友评论

          本文标题:NDK基础(二)——数组、全局变量、RegisterNative

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