为什么AssetManger.list()这么慢?AssetManger、list

由网友(绝傲)分享简介:我试图来填充存储在SD卡。如该资产APK文件存储的混合物一个ListView。使用 TraceView ,我可以看到 AssetManager.list()的性能差相比, File.listFiles(),虽然我使用了SD卡的文件名过滤器。I'm trying to populate a ListView with...

我试图来填充存储在SD卡。如该资产APK文件存储的混合物一个ListView。使用 TraceView ,我可以看到 AssetManager.list()的性能差相比, File.listFiles(),虽然我使用了SD卡的文件名过滤器。

I'm trying to populate a ListView with a mixture of files stored on the SDcard AND stored as assets in the APK. Using TraceView, I can see that the performance of AssetManager.list() is poor in comparison to File.listFiles(), even though I'm using a filename filter for the SDcard.

下面是一个从文件夹返回的SD卡所有的PNG文件的简单方法:

Here is a simple method that returns all the png files from a folder on the SDcard:

// 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;
}

我在这里调用该方法,它需要12ms左右检索16个文件:

I invoke that method here and it takes about 12ms to retrieve 16 files:

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方法需要49ms检索约6个文件只是名字!

Whereas the am.list method takes 49ms to retrieve just the names of about 6 files!

// 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资产有多少?我知道,资产COM pressed,但我只取资产的名字,我还以为会被存储在一个表中的某个地方。

Can anyone explain why the performance would be so poor? Is the performance proportional to the number of assets stored in the APK? I'm aware that assets are compressed, but I'm only fetching the names of the assets, which I thought would be stored in a table somewhere.

推荐答案

Coverdriven的评论存储在什么地方一表的启发我解决我自己的问题,我一直在拖延了一段时间。

Coverdriven's comment "stored in a table somewhere" inspired me to solve my own problem which I've been putting off for a while.

这不接OP,但确实提供了一种不同的方法,它处理CommonsWare的解决方案不,除非你去哪个递归(当然这是另一种可能的解决方案)子文件夹。它是专门针对具有子文件夹中有大量的资产应用程序。

This doesn't answer the OP but does offer a different approach and it handles subfolders which CommonsWare's solution doesn't unless you go recursive (which of course is another possible solution). It's specifically aimed at apps which have a large number of assets in subfolders.

我添加了一个ANT pre-build目标来运行这个命令(我是在Windows上)

I added an ANT pre-build target to run this command (I'm on Windows)

dir assets /b /s /A-d > resrawassetfiles

这将创建一个递归(/秒),准系统(/ B)的所有文件,但不包括目录项的清单(/ A-D)在我的资产文件夹中。

This creates a recursive (/s), barebones (/b) listing of all files, excluding directory entries (/A-d) in my assets folder.

然后我创建了这个类assetfiles的静态内容加载到一个HashMap,关键哪些是文件名和值的完整路径。

I then created this class to statically load the contents of assetfiles into a hashmap, the key of which is the filename and the value the full path

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(文件名)返回,我可以传递给AssetManager.open()的完整路径。得多快!

To use it, I simply call AssetFiles.getFilename(filename) which returns the full path which I can pass to AssetManager.open(). Much much faster!

NB。我还没有完成这个类和它的尚未硬化的,所以你需要添加相应的异常渔获物和行动。这也是相当具体的我在我所有的资产都应用子文件夹中,它们又位于资产文件夹的子文件夹(见FILES_ROOT),但容易适应您的情况。

NB. I haven't finished this class and it's not hardened yet so you'll need to add appropriate exception catches and actions. It's also quite specific to my app in that all of my assets are in subfolders which are in turn located in a subfolder of the assets folder (see FILES_ROOT) but easy to adapt to your situation.

请注意还需要更换反斜杠,因为Windows生成assetfiles上市,与斜线。你可以在OSX和* nix平台上消除这种。

Note also the need to replace backslashes, since Windows generates the assetfiles listing, with forward slashes. You could eliminate this on OSX and *nix platforms.

阅读全文

相关推荐

最新文章