本文轉載自: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);
}
}
代碼分析:
判斷步驟:
- 首先對Uri的authority進行判斷。是document類型的Uri還是普通的media類型的Uri。
- 由於document類型有兩種:media和download類型,所以需要進一步判斷。因爲這裏涉及Uri的id部分不同。
- 如果是普通類型,那麼和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()
方法來獲取表中的文件路徑。最終達到解碼圖片的目的。
參考
《第一行代碼》