兼容Android 19以上版本获取图片路径的方式

文章目录

  • 打开相册的方式
  • URI
  • example
    • 从图片获取到的uri格式为:
    • 从图库获取到的uri格式为:
    • 通过ACTION_PICK方式得到的URI通常格式为:
    • 通过ACTION_GET_CONTENT方式得到的URI通常为:
  • 参考

打开相册的方式

  • Intent.ACTION_PICK

默认打开图库,打开默认是缩略图界面,还需要进一步点开查看,通常用来选择指定URI下的资源。

  • Intent.ACTION_GET_CONTENT

4.4以下默认打开缩略图。4.4以上打开文件管理器供选择,选择图库打开为缩略图页面,选择图片打开为原图浏览,支持多选。

  • Intent.ACTION_OPEN_DOCUMENT(API19)

仅限4.4或以上使用默认打开原图,支持多选。

URI

Uri分为三个部分【域名://主机名/路径/id】

example

content://media/extenral/images/media/17766
content://com.android.providers.media.documents/document/image:2706
file://com.xxxx.xxxxx

从图片获取到的uri格式为:

content://com.android.providers.media.documents/document/image%3A35144【不可直接得到路径,需要进行转化】

从图库获取到的uri格式为:

content://media/external/images/media/35144

通过ACTION_PICK方式得到的URI通常格式为:

content://media/external/images/media/35144

通过ACTION_GET_CONTENT方式得到的URI通常为:

content://media/extenral/images/media/17766
content://com.android.providers.media.documents/document/image:2706

其中主机名可能为如下几种中的一种,直接通过URI查询ContentProvider,将会得到空路径,需要转换:

1、com.android.externalstorage.documents
2、com.android.providers.downloads.documents
3、com.android.providers.media.documents

因此适配不同版本获取图片路径的关键就是适配解析URI的方式。

代码如下:

发起请求:

final PackageManager packageManager = mContext.getPackageManager();
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setDataAndType( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
final List<ResolveInfo> list = packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
 //  当存在可用的程序才调用,否则会报错
if (list.size() > 0) {
     startActivityForResult(intent, HeadPreviewActivity.REQUEST_CODE_PICK_IMAGE);
} else {
     LogUtil.e(TAG, "no application with ACTION_GET_CONTENT");
     return;
}

解析URI的方法如下:

/**
     * 根据Uri获取图片的绝对路径
     *
     * @param context 上下文对象
     * @param uri     图片的Uri
     * @return 如果Uri对应的图片存在, 那么返回该图片的绝对路径, 否则返回null
     */
    public static String getRealPathFromUri(Context context, Uri uri) {

        // Uri分为三个部分   域名://主机名/路径/id
        // content://media/extenral/images/media/17766
        // content://com.android.providers.media.documents/document/image:2706
        // file://com.xxxx.xxxxx ---- 7.0 有限制

        int sdkVersion = Build.VERSION.SDK_INT;
        if (sdkVersion >= 19) { // api >= 19
            return getRealPathFromUriAboveApi19(context, uri);
        } else { // api < 19
            return getRealPathFromUriBelowAPI19(context, uri);
        }
    }

    /**
     * 适配api19以下(不包括api19),根据uri获取图片的绝对路径
     *
     * @param context 上下文对象
     * @param uri     图片的Uri
     * @return 如果Uri对应的图片存在, 那么返回该图片的绝对路径, 否则返回null
     */
    private static String getRealPathFromUriBelowAPI19(Context context, Uri uri) {
        final String scheme = uri.getScheme();
        String data = null;
        if (scheme == null)
            data = uri.getPath();
        else if (ContentResolver.SCHEME_FILE.equals(scheme)) {
            data = uri.getPath();
        } else if (ContentResolver.SCHEME_CONTENT.equals(scheme)) {
            data = getDataColumn(context, uri, null, null);
        }
        return data;
    }

    /**
     * 适配api19及以上,根据uri获取图片的绝对路径
     *
     * @param context 上下文对象
     * @param uri     图片的Uri
     * @return 如果Uri对应的图片存在, 那么返回该图片的绝对路径, 否则返回null
     */
    @SuppressLint("NewApi")
    private static String getRealPathFromUriAboveApi19(Context context, Uri uri) {
        String filePath = null;
        if (DocumentsContract.isDocumentUri(context, uri)) {
            // 如果是document类型的 uri, 则通过document id来进行处理
            String documentId = DocumentsContract.getDocumentId(uri);
            if (isMediaDocument(uri)) { // MediaProvider
                final String[] divide = documentId.split(":");
                final String type = divide[0];
                Uri mediaUri = null;
                if ("image".equals(type)) {
                    mediaUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
                } else if ("video".equals(type)) {
                    mediaUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
                } else if ("audio".equals(type)) {
                    mediaUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
                } else {
                    return null;
                }
                String selection = BaseColumns._ID + "=?";
                String[] selectionArgs = {divide[1]};
                filePath = getDataColumn(context, mediaUri, selection, selectionArgs);
            } else if (isDownloadsDocument(uri)) { // DownloadsProvider
                Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(documentId));
                filePath = getDataColumn(context, contentUri, null, null);
            }else if(isExternalStorageDocument(uri)) {
                String [] split = documentId.split(":");
                if(split.length >= 2) {
                    String type = split[0];
                    if("primary".equalsIgnoreCase(type)) {
                        filePath = Environment.getExternalStorageDirectory() + "/" + split[1];
                    }
                }
            }
        } else if (ContentResolver.SCHEME_CONTENT.equalsIgnoreCase(uri.getScheme())){
            // 如果是 content 类型的 Uri
            filePath = getDataColumn(context, uri, null, null);
        } else if (ContentResolver.SCHEME_FILE.equals(uri.getScheme())) {
            // 如果是 file 类型的 Uri,直接获取图片对应的路径
            filePath = uri.getPath();
        }
        return filePath;
    }

    /**
     * 获取数据库表中的 _data 列,即返回Uri对应的文件路径
     * @return
     */
    private static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
        String path = null;

        String[] projection = new String[]{MediaStore.Images.Media.DATA};
        Cursor cursor = null;
        try {
            cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
            if (cursor != null && cursor.moveToFirst()) {
                int columnIndex = cursor.getColumnIndexOrThrow(projection[0]);
                path = cursor.getString(columnIndex);
            }
        } catch (Exception e) {
            if (cursor != null) {
                cursor.close();
            }
        }
        return path;
    }

    /**
     * @param uri the Uri to check
     * @return Whether the Uri authority is MediaProvider
     */
    private static boolean isMediaDocument(Uri uri) {
        return "com.android.providers.media.documents".equals(uri.getAuthority());
    }

    /**
     * @param uri the Uri to check
     * @return Whether the Uri authority is DownloadsProvider
     */
    private static boolean isDownloadsDocument(Uri uri) {
        return "com.android.providers.downloads.documents".equals(uri.getAuthority());
    }

    private static boolean isExternalStorageDocument(Uri uri) {
        return "com.android.externalstorage.documents".equals(uri.getAuthority());
    }

参考

  • android 系统相册调用,各版本的区别总结
  • Android 如何選取圖片或是檔案?

你可能感兴趣的:(Android)