打开小米的文件管理器,我们很快会看到如下图所示的界面:
其中,会把各种文件分类显示。并且显示出每种文件的个数。
这是怎么做到的呢?当然不是每次启动都查询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 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 sDocMimeTypesSet = new HashSet() {
{
add("text/plain");
add("text/plain");
add("application/pdf");
add("application/msword");
add("application/vnd.ms-excel");
add("application/vnd.ms-excel");
}
};
这样,我们就清楚了小米文件管理器是如何通过MediaStore的功能来实现很快找出各种类型的文件的了。