为何AssetManger.list()这么慢?
作者:互联网
我正在尝试使用混合存储在SD卡中和存储为APK中资产的文件填充ListView.使用TraceView,我可以看到AssetManager.list()的性能与File.listFiles()相比是很差的,即使我为SD卡使用了文件名过滤器.
这是一个简单的方法,可以从SD卡上的文件夹返回所有png文件:
// The folder on SDcard may contain files other than png, so filter them out
private File[] getMatchingFiles(File path) {
File[] flFiles = path.listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
name = name.toLowerCase();
return name.endsWith(".png");
}
});
return flFiles;
}
我在这里调用该方法,大约需要12毫秒来检索16个文件:
final String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)||Environment.MEDIA_SHARED.equals(state)) {
File path = Environment.getExternalStoragePublicDirectory(getResources().getString(R.string.path_dir));
if (path.exists()){
File[] files = getMatchingFiles(path);
...
而am.list方法需要49毫秒才能检索大约6个文件的名称!
// Get all filenames from specific Asset Folder and store them in String array
AssetManager am = getAssets();
String path = getResources().getString(R.string.path_dir);
String[] fileNames = am.list(path);
...
谁能解释为什么性能这么差?性能与APK中存储的资产数量成正比吗?我知道资产已压缩,但我只是在获取资产的名称,我认为这些名称将存储在表的某个地方.
解决方法:
Coverdrive的评论“存储在桌子上的某处”启发了我解决自己的问题,这一问题我已经推迟了一段时间.
这不能满足OP的要求,但是可以提供不同的方法,它可以处理CommonsWare解决方案不会提供的子文件夹,除非您进行递归操作(当然这是另一种可能的解决方案).它专门针对子文件夹中具有大量资产的应用程序.
我添加了一个ANT预先构建目标来运行此命令(我在Windows上)
dir assets /b /s /A-d > res\raw\assetfiles
这将创建所有文件的递归(/ s),准系统(/ b)列表,但不包括我的资产文件夹中的目录条目(/ A-d).
然后,我创建了该类,以将资产文件的内容静态加载到哈希图中,其关键是文件名和完整路径的值
public class AssetFiles {
// create a hashmap of all files referenced in res/raw/assetfiles
/*map of all the contents of assets located in the subfolder with the name specified in FILES_ROOT
the key is the filename without path, the value is the full path relative to FILES_ROOT
includes the root, e.g. harmonics_data/subfolder/file.extension - this can be passed
directly to AssetManager.open()*/
public static HashMap<String, String> assetFiles = new HashMap<String, String>();
public static final String FILES_ROOT = "harmonics_data";
static {
String line;
String filename;
String path;
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(TidesPlannerApplication.getContext().getResources().openRawResource(R.raw.assetfiles)));
while ((line = reader.readLine()) != null) {
// NB backlash (note the escape) is specific to Windows
filename = line.substring(line.lastIndexOf("\\")+1);
path = line.substring(line.lastIndexOf(FILES_ROOT)).replaceAll("\\\\","/");;
assetFiles.put(filename, path);
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static boolean exists(String filename){
return assetFiles.containsKey(filename);
}
public static String getFilename(String filename){
if (exists(filename)){
return assetFiles.get(filename);
} else {
return "";
}
}
}
要使用它,我只需调用AssetFiles.getFilename(filename)即可,它返回可以传递给AssetManager.open()的完整路径.快得多!
NB.我尚未完成本课程,并且尚未进行强化,因此您需要添加适当的异常捕获和操作.它对我的应用程序也非常特定,因为我所有资产都位于子文件夹中,这些子文件夹又位于资产文件夹的子文件夹中(请参阅FILES_ROOT),但很容易适应您的情况.
还请注意需要替换反斜杠,因为Windows会使用正斜杠来替换资产文件列表.您可以在OSX和* nix平台上消除此问题.
标签:android,android-sdcard 来源: https://codeday.me/bug/20191010/1888118.html