其他分享
首页 > 其他分享> > 为何AssetManger.list()这么慢?

为何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