ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

为何AssetManger.list()这么慢?

2019-10-10 18:26:58  阅读:200  来源: 互联网

标签:android android-sdcard


我正在尝试使用混合存储在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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有