JNI 方法,如 FindClass
,GetMethodID
,GetFieldID
是昂贵的操作,保证在 JVM 的生命周期内生成相同的结果。由于这些操作很耗时,因此明智的做法是将结果存储在某个地方以便稍后在本机侧重用(这就是缓存)。
JNI 缓存仅涉及这些 JNI 函数调用。如果您想缓存任何其他 C++ 或 Java 对象,这是一个不同的话题。(只是为了清楚起见)。
缓存的类、方法和字段不依赖于它们被检索的线程,因此它们在不同的线程之间是有效的。最多,在使用 Set<type>Field
或 Get<type>Field
获取或设置某个对象的字段时,您必须执行线程安全操作。
由于 FindClass 返回对 class 对象的本地引用,因此您必须将其转换为全局引用,以确保在检索它的函数结束后重复使用它。您可以通过使用 NewGlobalReference 来实现这一点:
jclass tmp_double_Class = env->FindClass( "java/lang/Double" );
double_Class = static_cast<jclass>( env->NewGlobalRef( tmp_double_Class ) );
if( double_Class == NULL )
return;
env->DeleteLocalRef( tmp_double_Class );
这里有一个JNI缓存话题的例子:
MyJni.cpp:
#define CHECK_JNI_EXCEPTION( JNIenv ) \
if( JNIenv->ExceptionCheck() )\
{\
JNIenv->ExceptionClear();\
return JNI_FALSE;\
}\
\
jclass point_Class;
jmethodID point_ctor_Method;
jfieldID point_x_Field;
jfieldID point_y_Field;
JNIEXPORT jboolean JNICALL Java_com_company_package_MyClass_nativeInit( JNIEnv * env,
jclass clazz )
{
jclass tmp_point_Class = env->FindClass( "android/graphics/Point" );
CHECK_JNI_EXCEPTION( env )
point_Class = static_cast<jclass>( env->NewGlobalRef( tmp_point_Class ) );
if( point_Class == NULL )
return JNI_FALSE;
env->DeleteLocalRef( tmp_point_Class );
point_ctor_Method = env->GetMethodID( point_Class, "<init>", "(II)V" );
CHECK_JNI_EXCEPTION( env )
point_x_Field = env->GetFieldID( point_Class, "x", "I" );
CHECK_JNI_EXCEPTION( env )
point_y_Field = env->GetFieldID( point_Class, "y", "I" );
CHECK_JNI_EXCEPTION( env )
return JNI_TRUE;
}
MyJni.java:
package com.company.package;
class MyClass {
private static native void nativeInit();
static {
System.loadLibrary( "mylib" );
nativeInit();
}
}
玩得愉快 ;)
JNI_OnLoad
中进行设置来实现此目的,在其他线程启动之前完成设置。有关此主题的深入了解,请参阅:http://developer.android.com/training/articles/smp.html - fadden