Android Uri to Path

本文转载自:http://www.jianshu.com/p/f9a63fcc0b91

起因

Android在4.4之后的版本(包括4.4)中,从相册中选取图片返回Uri进行了改动。所以我们无法通过该Uri来取得文件路径,从而解码图片,将其显示出来。

在4.3或以下可以直接用Intent.ACTION_GET_CONTENT打开相册;在4.4或以上,官方建议用ACTION_OPEN_DOCUMENT打开相册

4.4之前的版本

在4.4之前的版本,返回的Uri如下:content://media/external/images/media/8302

我们可以通过ContentResolver的查询方法来获取路径:

Uri uri = "content://media/external/images/media/8302";
String imagePath = getImagePath(uri, null);
private String getImagePath(Uri uri, String selection) {
        String path = null;
        Cursor cursor = getContentResolver().query(uri, null, selection, null, null);
        if (cursor != null) {
            if (cursor.moveToFirst()) {
                path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
            }

            cursor.close();
        }
        return path;
    }

代码分析,当我们通过uri得到了相册数据库图片的表,然后通过索引MediaStore.Images.Media.DATA获取所得行的"_data"列的值。这样我们就得到了具体的文件路径,可以通过创建输入流来获取相应的Bitmap,并进行显示。

4.4之后的版本,包括4.4

在4.4之后的,包括4.4的版本,返回的Uri有可能是以下的一种:

  • content://com.android.providers.media.documents/document/image%3A8302
  • content://com.android.providers.downloads.documents/document/5
  • content://media/external/images/media/8302

我们不能直接通过前两种Uri直接获取到对应的表,所以需要"翻译一下":

private void handleImageOnKitKat(Intent data) {
        String imagePath = null;
        Uri uri = data.getData();

        if (DocumentsContract.isDocumentUri(this, uri)) {
            String docId = DocumentsContract.getDocumentId(uri);
            if ("com.android.providers.media.documents".equals(uri.getAuthority())) {
                //Log.d(TAG, uri.toString());
                String id = docId.split(":")[1];
                String selection = MediaStore.Images.Media._ID + "=" + id;
                imagePath = getImagePath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection);
            } else if ("com.android.providers.downloads.documents".equals(uri.getAuthority())) {
                //Log.d(TAG, uri.toString());
                Uri contentUri = ContentUris.withAppendedId(
                        Uri.parse("content://downloads/public_downloads"),
                        Long.valueOf(docId));
                imagePath = getImagePath(contentUri, null);
            }
        } else if ("content".equalsIgnoreCase(uri.getScheme())) {
            //Log.d(TAG, "content: " + uri.toString());
            imagePath = getImagePath(uri, null);
        }
    }

代码分析:

判断步骤:

  1. 首先对Uri的authority进行判断。是document类型的Uri还是普通的media类型的Uri。
  2. 由于document类型有两种:media和download类型,所以需要进一步判断。因为这里涉及Uri的id部分不同。
  3. 如果是普通类型,那么和4.4之前的处理完全一样。可以直接通过Uri获取文件路径。

如果是media类型的document Uri,我们首先通过DocumentsContract.getDocumentId(uri);获取到"image%3A8302"。然后通过String.split方法来获取真正的id。

这里为什么用":"来作为分隔符我也不是很清楚...而且还学到一个东西ContentResolver.query()方法中selection参数可以不用占位符"?"直接获取指定想要的列。

MediaStore.Images.Media._ID指的是我们获取到指定image文件的id在表中的列名。MediaStore.Images.Media.EXTERNAL_CONTENT_URI则是相册图片表真正的标示符。

这里的Uri获取是通过打开相册选定图片后,返回的Intent中获取的。

当我们获取到选中图片真正的Uri后,就可以通过之前的getImagePath()方法来获取表中的文件路径。最终达到解码图片的目的。

参考

Android 4.4从图库选择图片,获取图片路径并裁剪

Android-Uri To Path

《第一行代码》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章