返回

有啥问题,详解系统应用根据Uri授予权限的正确姿势

Android

在我们的印象中,Android6.0以后访问外部的媒体资源文件都是需要申请READ_EXTERNAL_STORAGE才可以正常访问,思考一个场景,假如我们不申请该权限,或者用户拒给了该权限,我们是否就无法对外部的文件进行操作了呢?

当然不是,只要合理的利用好ContentProvider机制就可以解决这个问题了,这里所说的合理利用不是指要开发者从头去构建一个ContentProvider,而是要善于利用已有的ContentProvider来达到目的。

如何利用已有的ContentProvider

其实关于媒体文件的ContentProvider从Android5.0就开始做了适配,为了向下兼容,所以才把READ_EXTERNAL_STORAGE这个权限放在了6.0才强制要求用户授权才能访问,为了支持更详细的权限控制,Android把媒体文件的权限分成了两大块,分别为READ和WRITE,WRITE权限负责增删改,READ权限负责查询和读取,READ权限的应用场景远大于WRITE权限,所以我们可以优先考虑只申请READ权限,这样就可以在Android6.0以上和Android6.0以下版本上都完美的适配了。

Android官方有提供了一个DocumentsContract类,是所有MediaDocumentsProvider的基类,里面封装了文件基本的信息,我们只需要利用该类就可以直接查询媒体文件了。

注意:虽然这里我们利用的是ContentProvider机制,但是并不会用到ContentResolver这个类,而是采用ContentResolver的升级版,MediaStore这个类,MediaStore这个类提供了更细节化的媒体文件操作,更为方便。

操作MediaStore

MediaStore.Images类:操作媒体图片,其中有一个静态内部类Thumbnails,负责查询图片的缩略图。

MediaStore.Video类:操作媒体视频,其中有一个静态内部类Thumbnails,负责查询视频的缩略图。

MediaStore.Audio类:操作媒体音频,其中有一个静态内部类Thumbnails,负责查询音频的缩略图。

MediaStore.Downloads类:操作媒体下载文件。

MediaStore.Files类:操作媒体文件,包含了图片、视频、音频和下载文件。

关于ContentProvider的查询语句类似于SQL语句,都可以使用selection、selectionArgs、sortOrder等参数进行筛选,其具体的用法和SQL一样,这里不做展开。

示例代码

根据路径直接查询文件信息:

Uri uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
String[] projection = new String[]{MediaStore.Images.Media._ID};
String selection = MediaStore.Images.Media.DATA + "=?";
String[] selectionArgs = new String[]{path};
Cursor cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
if (cursor != null) {
    while (cursor.moveToNext()) {
        int id = cursor.getInt(cursor.getColumnIndex(MediaStore.Images.Media._ID));
        // 根据id获取其他信息
    }
    cursor.close();
}

查询媒体的缩略图:

Uri uri = MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI;
String[] projection = new String[]{MediaStore.Images.Thumbnails._ID};
String selection = MediaStore.Images.Thumbnails.IMAGE_ID + "=?";
String[] selectionArgs = new String[]{id};
Cursor cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
if (cursor != null) {
    while (cursor.moveToNext()) {
        int thumbnailId = cursor.getInt(cursor.getColumnIndex(MediaStore.Images.Thumbnails._ID));
        // 根据id获取缩略图
    }
    cursor.close();
}