美文网首页Android-NDK/JNI音视频开发进阶
Android JNI 调用时缓存字段和方法 ID

Android JNI 调用时缓存字段和方法 ID

作者: glumes | 来源:发表于2018-07-09 10:00 被阅读3次

在 JNI 去调用 Java 的方法和访问字段时,最先要做的操作就是获得对应的类以及对应的方法 id。

事实上,通过 FindClass 、GetFieldID、GetMethodID 去找到对应的信息是很耗时的,如果方法被频繁调用,那么肯定不能每次都去查找对应的信息,有必要将它们缓存起来,在下一次调用时,直接使用缓存内容就好了。

缓存有两种方式,分别是使用时缓存和初始化时缓存。

使用时缓存

使用时缓存,就是在调用时查找一次,然后将它缓存成 static 变量,这样下次调用时就已经被初始化过了。

直到内存释放了,才会缓存失效。

extern "C"
JNIEXPORT void JNICALL
Java_com_glumes_cppso_jnioperations_CacheFieldAndMethodOps_staticCacheField(JNIEnv *env, jobject instance, jobject animal) {
    static jfieldID fid = NULL; // 声明为 static 变量进行缓存
    // 两种方法都行
//    jclass cls = env->GetObjectClass(animal);
    jclass cls = env->FindClass("com/glumes/cppso/model/Animal");
    jstring jstr;
    const char *c_str;
    // 从缓存中查找
    if (fid == NULL) {
        fid = env->GetFieldID(cls, "name", "Ljava/lang/String;");
        if (fid == NULL) {
            return;
        }
    } else {
        LOGD("field id is cached");
    }
    jstr = (jstring) env->GetObjectField(animal, fid);
    c_str = env->GetStringUTFChars(jstr, NULL);
    if (c_str == NULL) {
        return;
    }
    env->ReleaseStringUTFChars(jstr, c_str);
    jstr = env->NewStringUTF("new name");
    if (jstr == NULL) {
        return;
    }
    env->SetObjectField(animal, fid, jstr);
}

通过声明为 static 变量进行缓存。但这种缓存方式显然有弊端,当多个调用者同时调用时,就会出现缓存多次的情况,并且每次调用时都要检查是否缓存过了。

初始化时缓存

在初始化时缓存,就是在类加载时,进行缓存。当类被加载进内存时,会先调用类的静态代码块,所以可以在类的静态代码块中进行缓存。

比如:

public class CacheFieldAndMethodOps extends BaseOperation {
    
    static {
        initCacheMethodId(); // 静态代码块中进行缓存
    }
    private static native void initCacheMethodId();
}

在静态代码块中,可以将所需要的字段 id 或者方法 id 缓存成全局变量。

具体代码如下:

// 全局变量,作为缓存方法 id
jmethodID InstanceMethodCache;

// 初始化加载时缓存方法 id
extern "C"
JNIEXPORT void JNICALL
Java_com_glumes_cppso_jnioperations_CacheFieldAndMethodOps_initCacheMethodId(JNIEnv *env, jclass type) {
    jclass cls = env->FindClass("com/glumes/cppso/model/Animal");
    InstanceMethodCache = env->GetMethodID(cls, "getName", "()Ljava/lang/String;");
}

在 JNI 中直接将方法 id 缓存成全局变量了,这样再调用时,就不要再进行一次查找了,并且避免了多个线程同时调用会多次查找的情况。

extern "C"
JNIEXPORT void JNICALL
Java_com_glumes_cppso_jnioperations_CacheFieldAndMethodOps_callCacheMethod(JNIEnv *env, jobject instance, jobject animal) {
    jstring name = (jstring) env->CallObjectMethod(animal, InstanceMethodCache);
    const char *c_name = env->GetStringUTFChars(name, NULL);
    LOGD("call cache method and value is %s", c_name);
}

小结

可以看出,如果不能预先知道方法和字段所在类的源码,那么在使用时缓存比较合理。但如果知道的话,在初始化时缓存优点较多,既避免了每次使用时检查,还避免了在多线程被调用的情况。

具体示例代码可参考我的 Github 项目,欢迎 Star。

https://github.com/glumes/AndroidDevWithCpp

欢迎关注微信公众号:【纸上浅谈】,获得最新文章推送~~

扫码关注

相关文章

  • Android JNI 调用时缓存字段和方法 ID

    在 JNI 去调用 Java 的方法和访问字段时,最先要做的操作就是获得对应的类以及对应的方法 id。 事实上,通...

  • 缓存

    将所需要存的字段 存入本地缓存中 使用时,再从本地缓存 中取出

  • JNI方法数组和引用

    JNI方法 步骤:1.获取jclass2.获取方法ID;jmethodID3.jni调用java的方法 数组 步骤...

  • Android 通过 JNI 访问 Java 字段和方法调用

    在前面的两篇文章中,介绍了 Android 通过 JNI 进行基础类型、字符串和数组的相关操作,并描述了 Java...

  • JNI相关知识点

    1、Android NDK开发:JNI基础篇 2、Android Studio NDK环境配置及JNI使用方法 3...

  • 微信小程序缓存setStorageSync

    在遇到一个字段的值其他页面也需要使用时,就可以将这个字段的值保存在缓存里。比如在小程序开发时,某个id是经常需要使...

  • Android JNI 篇 - 从入门到放弃

    一、JNI 涉及的名词概念 二、JNI 在 Android Studio 搭建 三、JNI 类型,方法对照表 四、...

  • 音视频学习(一)JNI入门

    前言 Android平台从一开始就支持C/C++了,Android支持JNI编程方式第三方应用完全可以通过JNI调...

  • JNI编程指南(二):字段和方法

    前言 上篇文章介绍了JNI中访问JVM中任意基本类型数据和字符串、数组这样的引用类型,这篇就简单介绍下JNI对JV...

  • JNI 入门

    ref: Android Studio开发JNI示例Android NDK 开发(二)JNI 传递参数和返回值An...

网友评论

    本文标题:Android JNI 调用时缓存字段和方法 ID

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