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

《第一行代碼》

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