Android: Improve cache logic in findClass()
This change adds guards to ensure that we only do a class look-up once when calling QJNIEnvironmentPrivate::findClass(). IF someone calls findClass() with an environment that does not contain a "valid" class loader, we should fallback to loadClass(), but only once. Change-Id: If5fc82956db889f3269bb33c98a16c49cae55def Reviewed-by: Yoann Lopes <yoann.lopes@theqtcompany.com>
This commit is contained in:
parent
cf8f369f85
commit
3d94a564f4
@ -80,38 +80,22 @@ static QString toDotEncodedClassName(const char *className)
|
||||
return QString::fromLatin1(className).replace(QLatin1Char('/'), QLatin1Char('.'));
|
||||
}
|
||||
|
||||
static jclass getCachedClass(const QString &classDotEnc)
|
||||
static jclass getCachedClass(const QString &classDotEnc, bool *isCached = 0)
|
||||
{
|
||||
QHash<QString, jclass>::iterator it = cachedClasses->find(classDotEnc);
|
||||
const bool found = (it != cachedClasses->end());
|
||||
|
||||
if (it == cachedClasses->end())
|
||||
return 0;
|
||||
if (isCached != 0)
|
||||
*isCached = found;
|
||||
|
||||
return it.value();
|
||||
return found ? it.value() : 0;
|
||||
}
|
||||
|
||||
static jclass findClass(const char *className, JNIEnv *env)
|
||||
static jclass loadClassDotEnc(const QString &classDotEnc, JNIEnv *env)
|
||||
{
|
||||
const QString &classDotEnc = toDotEncodedClassName(className);
|
||||
jclass clazz = getCachedClass(classDotEnc);
|
||||
if (clazz != 0)
|
||||
return clazz;
|
||||
|
||||
jclass fclazz = env->FindClass(className);
|
||||
if (!exceptionCheckAndClear(env)) {
|
||||
clazz = static_cast<jclass>(env->NewGlobalRef(fclazz));
|
||||
env->DeleteLocalRef(fclazz);
|
||||
}
|
||||
|
||||
cachedClasses->insert(classDotEnc, clazz);
|
||||
return clazz;
|
||||
}
|
||||
|
||||
static jclass loadClass(const char *className, JNIEnv *env)
|
||||
{
|
||||
const QString &classDotEnc = toDotEncodedClassName(className);
|
||||
jclass clazz = getCachedClass(classDotEnc);
|
||||
if (clazz != 0)
|
||||
bool isCached = false;
|
||||
jclass clazz = getCachedClass(classDotEnc, &isCached);
|
||||
if (clazz != 0 || isCached)
|
||||
return clazz;
|
||||
|
||||
QJNIObjectPrivate classLoader = QtAndroidPrivate::classLoader();
|
||||
@ -130,6 +114,11 @@ static jclass loadClass(const char *className, JNIEnv *env)
|
||||
return clazz;
|
||||
}
|
||||
|
||||
inline static jclass loadClass(const char *className, JNIEnv *env)
|
||||
{
|
||||
return loadClassDotEnc(toDotEncodedClassName(className), env);
|
||||
}
|
||||
|
||||
typedef QHash<QString, jmethodID> JMethodIDHash;
|
||||
Q_GLOBAL_STATIC(JMethodIDHash, cachedMethodID)
|
||||
|
||||
@ -224,12 +213,28 @@ JNIEnv *QJNIEnvironmentPrivate::operator->()
|
||||
|
||||
jclass QJNIEnvironmentPrivate::findClass(const char *className, JNIEnv *env)
|
||||
{
|
||||
jclass clazz = 0;
|
||||
if (env != 0)
|
||||
clazz = ::findClass(className, env);
|
||||
const QString &classDotEnc = toDotEncodedClassName(className);
|
||||
bool isCached = false;
|
||||
jclass clazz = getCachedClass(classDotEnc, &isCached);
|
||||
|
||||
if (clazz == 0)
|
||||
clazz = loadClass(className, QJNIEnvironmentPrivate());
|
||||
const bool found = (clazz != 0) || (clazz == 0 && isCached);
|
||||
|
||||
if (found)
|
||||
return clazz;
|
||||
|
||||
if (env != 0) { // We got an env. pointer (We expect this to be the right env. and call FindClass())
|
||||
jclass fclazz = env->FindClass(className);
|
||||
if (!exceptionCheckAndClear(env)) {
|
||||
clazz = static_cast<jclass>(env->NewGlobalRef(fclazz));
|
||||
env->DeleteLocalRef(fclazz);
|
||||
}
|
||||
|
||||
if (clazz != 0)
|
||||
cachedClasses->insert(classDotEnc, clazz);
|
||||
}
|
||||
|
||||
if (clazz == 0) // We didn't get an env. pointer or we got one with the WRONG class loader...
|
||||
clazz = loadClassDotEnc(classDotEnc, QJNIEnvironmentPrivate());
|
||||
|
||||
return clazz;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user