android - 为什么 AssetManger.list() 这么慢?

标签 android android-sdcard

我正在尝试使用存储在 SD 卡上并作为 Assets 存储在 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;
}

我在这里调用该方法,检索 16 个文件大约需要 12 毫秒:

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 中存储的 Assets 数量成正比?我知道 Assets 是压缩的,但我只是获取 Assets 的名称,我认为这些名称会存储在某个表中。

最佳答案

Coverdriven 的评论“存储在某处的表中”启发了我去解决我自己的问题,这个问题我已经推迟了一段时间。

这不会回答 OP 但确实提供了一种不同的方法并且它处理 CommonsWare 的解决方案不处理的子文件夹,除非你递归(这当然是另一种可能的解决方案)。它专门针对在子文件夹中拥有大量资源的应用。

我添加了一个 ANT 预构建目标来运行这个命令(我在 Windows 上)

dir assets /b /s /A-d > res\raw\assetfiles

这将创建所有文件的递归 (/s)、准系统 (/b) 列表,不包括我的 Assets 文件夹中的目录条目 (/A-d)。

然后我创建了这个类来将 assetfiles 的内容静态加载到一个 hashmap 中,hashmap 的键是文件名,值是完整路径

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() 的完整路径。快多了!

注意。我还没有完成这个类(class),它还没有强化,所以你需要添加适当的异常捕获和操作。它也非常适合我的应用程序,因为我的所有 Assets 都位于子文件夹中,而这些子文件夹又位于 Assets 文件夹的子文件夹中(请参阅 FILES_ROOT),但很容易适应您的情况。

另请注意,需要替换反斜杠,因为 Windows 会生成带有正斜杠的 Assets 文件列表。您可以在 OSX 和 *nix 平台上消除它。

关于android - 为什么 AssetManger.list() 这么慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12636861/

相关文章:

android - 什么是 Context.getExternalMediaDir()?

java - 访问谷歌日历时出现空指针异常

java - 无法使用对象列表写入/读取文件

java - 从 Spring MVC Controller 推送实时数据

android - 将/data/data 中的文件夹复制到 sdcard,反之亦然

android - 仅从媒体存储中获取前 100 行图像

android - 无法将 null 传递给 execute(); android 4.0中AsyncTask的方法

java - Android - MediaPlayer 继续前进

Android - 当应用程序安装在 SD 卡上时,内部存储与外部存储

android - 如果外部存储不可用怎么办?