时间:2021-05-21
在 JNI 去调用 Java 的方法和访问字段时,最先要做的操作就是获得对应的类以及对应的方法 id。
事实上,通过 FindClass 、GetFieldID、GetMethodID 去找到对应的信息是很耗时的,如果方法被频繁调用,那么肯定不能每次都去查找对应的信息,有必要将它们缓存起来,在下一次调用时,直接使用缓存内容就好了。
缓存有两种方式,分别是使用时缓存和初始化时缓存。
使用时缓存
使用时缓存,就是在调用时查找一次,然后将它缓存成 static 变量,这样下次调用时就已经被初始化过了。
直到内存释放了,才会缓存失效。
extern "C"JNIEXPORT void JNICALLJava_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 缓存成全局变量。
具体代码如下:
// 全局变量,作为缓存方法 idjmethodID InstanceMethodCache;// 初始化加载时缓存方法 idextern "C"JNIEXPORT void JNICALLJava_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 JNICALLJava_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 项目 https://github.com/glumes/AndroidDevWithCpp,欢迎 Star。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
方法一:加If-Modified-Since头xmlhttp多次调用时它却总是显示缓存页面,尝试在php或asp中加入相应的http头明确不要缓存,也没什么效果
常用的就是jni,jnative(基于jni封装了自己的jar包)注意:java调用dll,必须dll里做了对应的处理。列如:方法名必须为_java_包名_类名
Android开发过程中为了实现代码的高效性,通常要调用本地c++代码,JNI是java语言提供的和c/c++相互沟通的机制,在使用opencv做图像处理时,通
1:按值传递是什么指的是在方法调用时,传递的参数是按值的拷贝传递。示例如下:publicclassTempTest{privatevoidtest1(inta)
本文实例讲述了Android编程使用缓存优化ListView的方法。分享给大家供大家参考,具体如下:ListView调用Adapter的getView方法获取每