Android: implement a simple cache mechanism for assets dirs.

AAssetManager_openDir is a pretty slow operation, so we are caching the most used dir contents.

Task-number: QTBUG-34464

Change-Id: If198f7dae0d6961291c992e6eb46839ba5455819
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@digia.com>
bb10
BogDan Vatra 2013-11-01 11:45:21 +02:00 committed by The Qt Project
parent c95e1567e9
commit 48dcdbe510
2 changed files with 53 additions and 26 deletions

View File

@ -43,20 +43,32 @@
#include "androidjnimain.h"
#include <QCoreApplication>
#include <QVector>
typedef QVector<QString> FilesList;
struct AndroidAssetDir
{
AndroidAssetDir(AAssetDir* ad)
{
const char *fileName;
while ((fileName = AAssetDir_getNextFileName(ad)))
m_items.push_back(QString::fromUtf8(fileName));
AAssetDir_close(ad);
}
FilesList m_items;
};
class AndroidAbstractFileEngineIterator: public QAbstractFileEngineIterator
{
public:
AndroidAbstractFileEngineIterator(QDir::Filters filters,
const QStringList &nameFilters,
AAssetDir *asset,
QSharedPointer<AndroidAssetDir> asset,
const QString &path)
: QAbstractFileEngineIterator(filters, nameFilters)
{
AAssetDir_rewind(asset);
const char *fileName;
while ((fileName = AAssetDir_getNextFileName(asset)))
m_items << fileName;
m_items = asset->m_items;
m_index = -1;
m_path = path;
}
@ -93,7 +105,7 @@ public:
private:
QString m_path;
QStringList m_items;
FilesList m_items;
int m_index;
};
@ -102,12 +114,11 @@ class AndroidAbstractFileEngine: public QAbstractFileEngine
public:
explicit AndroidAbstractFileEngine(AAsset *asset, const QString &fileName)
{
m_assetDir = 0;
m_assetFile = asset;
m_fileName = fileName;
}
explicit AndroidAbstractFileEngine(AAssetDir *asset, const QString &fileName)
explicit AndroidAbstractFileEngine(QSharedPointer<AndroidAssetDir> asset, const QString &fileName)
{
m_assetFile = 0;
m_assetDir = asset;
@ -119,8 +130,6 @@ public:
~AndroidAbstractFileEngine()
{
close();
if (m_assetDir)
AAssetDir_close(m_assetDir);
}
virtual bool open(QIODevice::OpenMode openMode)
@ -188,7 +197,7 @@ public:
FileFlags flags(ReadOwnerPerm|ReadUserPerm|ReadGroupPerm|ReadOtherPerm|ExistsFlag);
if (m_assetFile)
flags |= FileType;
if (m_assetDir)
if (!m_assetDir.isNull())
flags |= DirectoryType;
return type & flags;
@ -233,19 +242,19 @@ public:
virtual Iterator *beginEntryList(QDir::Filters filters, const QStringList &filterNames)
{
if (m_assetDir)
if (!m_assetDir.isNull())
return new AndroidAbstractFileEngineIterator(filters, filterNames, m_assetDir, m_fileName);
return 0;
}
private:
AAsset *m_assetFile;
AAssetDir *m_assetDir;
QSharedPointer<AndroidAssetDir> m_assetDir;
QString m_fileName;
};
AndroidAssetsFileEngineHandler::AndroidAssetsFileEngineHandler()
AndroidAssetsFileEngineHandler::AndroidAssetsFileEngineHandler():m_assetsCache(std::max(5, qgetenv("QT_ANDROID_MAX_ASSETS_CACHE_SIZE").toInt()))
{
m_assetManager = QtAndroid::assetManager();
}
@ -264,25 +273,37 @@ QAbstractFileEngine * AndroidAssetsFileEngineHandler::create(const QString &file
int prefixSize=8;
m_path.clear();
QByteArray path;
if (!fileName.endsWith(QLatin1Char('/'))) {
m_path = fileName.toUtf8();
path = fileName.toUtf8();
AAsset *asset = AAssetManager_open(m_assetManager,
m_path.constData() + prefixSize,
path.constData() + prefixSize,
AASSET_MODE_BUFFER);
if (asset)
return new AndroidAbstractFileEngine(asset, fileName);
}
if (!m_path.size())
m_path = fileName.left(fileName.length() - 1).toUtf8();
if (!path.size())
path = fileName.left(fileName.length() - 1).toUtf8();
AAssetDir *assetDir = AAssetManager_openDir(m_assetManager, m_path.constData() + prefixSize);
if (assetDir) {
if (AAssetDir_getNextFileName(assetDir))
return new AndroidAbstractFileEngine(assetDir, fileName);
else
AAssetDir_close(assetDir);
m_assetsCacheMutext.lock();
QSharedPointer<AndroidAssetDir> *aad = m_assetsCache.object(path);
m_assetsCacheMutext.unlock();
if (!aad) {
AAssetDir *assetDir = AAssetManager_openDir(m_assetManager, path.constData() + prefixSize);
if (assetDir) {
if (AAssetDir_getNextFileName(assetDir)) {
aad = new QSharedPointer<AndroidAssetDir>(new AndroidAssetDir(assetDir));
m_assetsCacheMutext.lock();
m_assetsCache.insert(path, aad);
m_assetsCacheMutext.unlock();
return new AndroidAbstractFileEngine(*aad, fileName);
} else {
AAssetDir_close(assetDir);
}
}
} else {
return new AndroidAbstractFileEngine(*aad, fileName);
}
return 0;
}

View File

@ -43,8 +43,13 @@
#define QANDROIDASSETSFILEENGINEHANDLER_H
#include <QtCore/private/qabstractfileengine_p.h>
#include <QCache>
#include <QMutex>
#include <QSharedPointer>
#include <android/asset_manager.h>
struct AndroidAssetDir;
class AndroidAssetsFileEngineHandler: public QAbstractFileEngineHandler
{
public:
@ -54,7 +59,8 @@ public:
private:
AAssetManager *m_assetManager;
mutable QByteArray m_path;
mutable QCache<QByteArray, QSharedPointer<AndroidAssetDir>> m_assetsCache;
mutable QMutex m_assetsCacheMutext;
};
#endif // QANDROIDASSETSFILEENGINEHANDLER_H