[MediaStore]小米文件管理器android版源码分析——数据来源

    打开小米的文件管理器,我们很快会看到如下图所示的界面:

[MediaStore]小米文件管理器android版源码分析——数据来源

其中,会把各种文件分类显示。并且显示出每种文件的个数。

这是怎么做到的呢?当然不是每次启动都查询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的功能来实现很快找出各种类型的文件的了。

你可能感兴趣的:(android,MediaStore)