美文网首页
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