打开小米的文件管理器,我们很快会看到如下图所示的界面:
其中,会把各种文件分类显示。并且显示出每种文件的个数。
这是怎么做到的呢?当然不是每次启动都查询sdcard和应用程序data目录文件啦,那样实在是太慢太愚蠢了。因为android框架的MediaStore已经为我们提供了相应的功能。对于各种类型的文件,都有一个ContentProvider提供相应的数据。我们需要通过正确的uri去查询相应的ContentProvider即可。
下面就从分析小米手机源码入手,看看是如何使用MediaStore的。
首先,以枚举的形式定义不同文件类型:
public enum FileCategory { All, Music, Video, Picture, Theme, Doc, Zip, Apk, Custom, Other, Favorite }
接着,设置各种文件查询的uri:
// query database String volumeName = "external"; Uri uri = Audio.Media.getContentUri(volumeName); //音频文件 refreshMediaCategory(FileCategory.Music, uri); uri = Video.Media.getContentUri(volumeName); //视频文件 refreshMediaCategory(FileCategory.Video, uri); uri = Images.Media.getContentUri(volumeName); //图片文件 refreshMediaCategory(FileCategory.Picture, uri); uri = Files.getContentUri(volumeName); //其他文件 refreshMediaCategory(FileCategory.Theme, uri); refreshMediaCategory(FileCategory.Doc, uri); refreshMediaCategory(FileCategory.Zip, uri); refreshMediaCategory(FileCategory.Apk, uri);
其中,MediaStore.Files包含了除音频文件、视频文件、图片文件之外的其他文件类型。
之后,我们看refreshMediaCategory方法中做了什么事情:
private boolean refreshMediaCategory(FileCategory fc, Uri uri) { String[] columns = new String[] { "COUNT(*)", "SUM(_size)" }; Cursor c = mContext.getContentResolver().query(uri, columns, buildSelectionByCategory(fc), null, null); if (c == null) { Log.e(LOG_TAG, "fail to query uri:" + uri); return false; } if (c.moveToNext()) { setCategoryInfo(fc, c.getLong(0), c.getLong(1)); Log.v(LOG_TAG, "Retrieved " + fc.name() + " info >>> count:" + c.getLong(0) + " size:" + c.getLong(1)); c.close(); return true; } return false; }
这里面进行了对ContentProvider的查询,根据buildSelectionByCategory方法中设置的条件来查询。
再来看看buildSelectionByCategory方法中的内容:
private String buildSelectionByCategory(FileCategory cat) { String selection = null; switch (cat) { case Theme: selection = FileColumns.DATA + " LIKE '%.mtz'"; break; case Doc: selection = buildDocSelection(); break; case Zip: selection = "(" + FileColumns.MIME_TYPE + " == '" + Util.sZipFileMimeType + "')"; break; case Apk: selection = FileColumns.DATA + " LIKE '%.apk'"; break; default: selection = null; } return selection; }
因为只有MediaStore.Files中的文件内容需要区分,因此按条件查询只需要对这个进行即可。
对于压缩文件(Zip)是:
public static String sZipFileMimeType = "application/zip";
对于文档文件(Doc)是:
private String buildDocSelection() { StringBuilder selection = new StringBuilder(); Iterator<String> iter = Util.sDocMimeTypesSet.iterator(); while(iter.hasNext()) { selection.append("(" + FileColumns.MIME_TYPE + "=='" + iter.next() + "') OR "); } return selection.substring(0, selection.lastIndexOf(")") + 1); }
其中,sDocMimeTypesSet是:
public static HashSet<String> sDocMimeTypesSet = new HashSet<String>() { { add("text/plain"); add("text/plain"); add("application/pdf"); add("application/msword"); add("application/vnd.ms-excel"); add("application/vnd.ms-excel"); } };
这样,我们就清楚了小米文件管理器是如何通过MediaStore的功能来实现很快找出各种类型的文件的了。