Android: Improve loading speed of individual assets
This change improves the loading speed of files stored in Android assets folder by caching the information about files already opened. Prior to the change, when creating a QFile or QFileInfo to an asset file, the engine would first scan all the file's directory and parent directories in order to cache all this in FolderIterator::m_assetsCache. Due to the nature of Android assets, it might be very slow, depending on the number of images in this tree. In this patch, individual file accesses will stop using FolderIterator and will simply open what is asked, caching the information about the resource in order to avoid to have to call the expensive AAssetManager_open if the file is accessed again (e.g. by QFileInfo). Fixes: QTBUG-101161 Change-Id: Iaedf4cdf83d5116053b51895a6795d43bc60f942 Pick-to: 6.4 6.3 6.2 5.15 Reviewed-by: Rami Potinkara <rami.potinkara@qt.io> Reviewed-by: Ville Voutilainen <ville.voutilainen@qt.io>bb10
parent
f53f709504
commit
edd983071e
|
|
@ -231,9 +231,10 @@ public:
|
|||
{
|
||||
Q_UNUSED(permissions);
|
||||
|
||||
if (m_isFolder || (openMode & QIODevice::WriteOnly))
|
||||
if (!m_assetInfo || m_assetInfo->type != AssetItem::Type::File || (openMode & QIODevice::WriteOnly))
|
||||
return false;
|
||||
close();
|
||||
if (m_assetFile)
|
||||
return true;
|
||||
m_assetFile = AAssetManager_open(m_assetManager, m_fileName.toUtf8(), AASSET_MODE_BUFFER);
|
||||
return m_assetFile;
|
||||
}
|
||||
|
|
@ -245,7 +246,6 @@ public:
|
|||
m_assetFile = 0;
|
||||
return true;
|
||||
}
|
||||
m_isFolder = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -286,10 +286,12 @@ public:
|
|||
{
|
||||
FileFlags commonFlags(ReadOwnerPerm|ReadUserPerm|ReadGroupPerm|ReadOtherPerm|ExistsFlag);
|
||||
FileFlags flags;
|
||||
if (m_assetFile)
|
||||
flags = FileType | commonFlags;
|
||||
else if (m_isFolder)
|
||||
flags = DirectoryType | commonFlags;
|
||||
if (m_assetInfo) {
|
||||
if (m_assetInfo->type == AssetItem::Type::File)
|
||||
flags = FileType | commonFlags;
|
||||
else if (m_assetInfo->type == AssetItem::Type::Folder)
|
||||
flags = DirectoryType | commonFlags;
|
||||
}
|
||||
return type & flags;
|
||||
}
|
||||
|
||||
|
|
@ -324,21 +326,42 @@ public:
|
|||
return;
|
||||
close();
|
||||
m_fileName = cleanedAssetPath(file);
|
||||
switch (FolderIterator::fileType(m_fileName)) {
|
||||
case AssetItem::Type::File:
|
||||
open(QIODevice::ReadOnly, std::nullopt);
|
||||
break;
|
||||
case AssetItem::Type::Folder:
|
||||
m_isFolder = true;
|
||||
break;
|
||||
case AssetItem::Type::Invalid:
|
||||
break;
|
||||
|
||||
{
|
||||
QMutexLocker lock(&m_assetsInfoCacheMutex);
|
||||
QSharedPointer<AssetItem> *assetInfoPtr = m_assetsInfoCache.object(m_fileName);
|
||||
if (assetInfoPtr) {
|
||||
m_assetInfo = *assetInfoPtr;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
QSharedPointer<AssetItem> *newAssetInfoPtr = new QSharedPointer<AssetItem>(new AssetItem);
|
||||
|
||||
m_assetInfo = *newAssetInfoPtr;
|
||||
m_assetInfo->name = m_fileName;
|
||||
m_assetInfo->type = AssetItem::Type::Invalid;
|
||||
|
||||
m_assetFile = AAssetManager_open(m_assetManager, m_fileName.toUtf8(), AASSET_MODE_BUFFER);
|
||||
|
||||
if (m_assetFile) {
|
||||
m_assetInfo->type = AssetItem::Type::File;
|
||||
} else {
|
||||
auto *assetDir = AAssetManager_openDir(m_assetManager, m_fileName.toUtf8());
|
||||
if (assetDir) {
|
||||
if (AAssetDir_getNextFileName(assetDir))
|
||||
m_assetInfo->type = AssetItem::Type::Folder;
|
||||
AAssetDir_close(assetDir);
|
||||
}
|
||||
}
|
||||
|
||||
QMutexLocker lock(&m_assetsInfoCacheMutex);
|
||||
m_assetsInfoCache.insert(m_fileName, newAssetInfoPtr);
|
||||
}
|
||||
|
||||
Iterator *beginEntryList(QDir::Filters filters, const QStringList &filterNames) override
|
||||
{
|
||||
if (m_isFolder)
|
||||
if (m_assetInfo && m_assetInfo->type == AssetItem::Type::Folder)
|
||||
return new AndroidAbstractFileEngineIterator(filters, filterNames, m_fileName);
|
||||
return nullptr;
|
||||
}
|
||||
|
|
@ -348,9 +371,14 @@ private:
|
|||
AAssetManager *m_assetManager = nullptr;
|
||||
// initialize with a name that can't be used as a file name
|
||||
QString m_fileName = "."_L1;
|
||||
bool m_isFolder = false;
|
||||
QSharedPointer<AssetItem> m_assetInfo;
|
||||
|
||||
static QCache<QString, QSharedPointer<AssetItem>> m_assetsInfoCache;
|
||||
static QMutex m_assetsInfoCacheMutex;
|
||||
};
|
||||
|
||||
QCache<QString, QSharedPointer<AssetItem>> AndroidAbstractFileEngine::m_assetsInfoCache(std::max(200, qEnvironmentVariableIntValue("QT_ANDROID_MAX_FILEINFO_ASSETS_CACHE_SIZE")));
|
||||
QMutex AndroidAbstractFileEngine::m_assetsInfoCacheMutex;
|
||||
|
||||
AndroidAssetsFileEngineHandler::AndroidAssetsFileEngineHandler()
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue