美文网首页Android Tech
Android Uri to Path

Android Uri to Path

作者: 狮_子歌歌 | 来源:发表于2016-10-08 00:03 被阅读3679次

    起因

    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有可能是以下的一种:

    我们不能直接通过前两种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()方法来获取表中的文件路径。最终达到解码图片的目的。

    实际效果

    Uri To Path.gif

    参考

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

    Android-Uri To Path

    《第一行代码》

    相关文章

      网友评论

      • 一个简单搬运工::的URL编码后是%3A,所以。。。
      • 妄想症患者_74a8:感谢分享!
      • 47fe3088500c:非常清晰 非常好 感谢分享...
      • slimvan:厉害了楼主,问题在这里得到解决。
        狮_子歌歌:@slimvan 谢谢:smile:
      • 莎莎氧oO:找了好久,,终于找到正确的答案,,感谢小编,,另外,还需要一个权限。
        <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
        狮_子歌歌:@o氧气oO 你可以打印出你返回的url看看
        莎莎氧oO:@FoolishDev 但是我还是遇到坑,,当选择跟目录的文件返回来时候,uri还是转换不了path。。
        狮_子歌歌:@o氧气oO 莫非大兄弟也是在看第一行代码遇到坑了吗

      本文标题:Android Uri to Path

      本文链接:https://www.haomeiwen.com/subject/axcuyttx.html