起因
Android在4.4之后的版本(包括4.4)中,從相冊(cè)中選取圖片返回Uri進(jìn)行了改動(dòng)榕莺。所以我們無(wú)法通過(guò)該Uri來(lái)取得文件路徑俐芯,從而解碼圖片,將其顯示出來(lái)钉鸯。
在4.3或以下可以直接用Intent.ACTION_GET_CONTENT打開相冊(cè);在4.4或以上,官方建議用ACTION_OPEN_DOCUMENT打開相冊(cè)
4.4之前的版本
在4.4之前的版本吧史,返回的Uri如下:content://media/external/images/media/8302
我們可以通過(guò)ContentResolver的查詢方法來(lái)獲取路徑:
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;
}
代碼分析,當(dāng)我們通過(guò)uri得到了相冊(cè)數(shù)據(jù)庫(kù)圖片的表唠雕,然后通過(guò)索引MediaStore.Images.Media.DATA
獲取所得行的"_data"列的值贸营。這樣我們就得到了具體的文件路徑,可以通過(guò)創(chuàng)建輸入流來(lái)獲取相應(yīng)的Bitmap及塘,并進(jìn)行顯示莽使。
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
我們不能直接通過(guò)前兩種Uri直接獲取到對(duì)應(yīng)的表,所以需要"翻譯一下":
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);
}
}
代碼分析:
判斷步驟:
- 首先對(duì)Uri的authority進(jìn)行判斷。是document類型的Uri還是普通的media類型的Uri亿笤。
- 由于document類型有兩種:media和download類型翎迁,所以需要進(jìn)一步判斷。因?yàn)檫@里涉及Uri的id部分不同净薛。
- 如果是普通類型汪榔,那么和4.4之前的處理完全一樣∷喟荩可以直接通過(guò)Uri獲取文件路徑痴腌。
如果是media類型的document Uri,我們首先通過(guò)DocumentsContract.getDocumentId(uri);
獲取到"image%3A8302"燃领。然后通過(guò)String.split方法來(lái)獲取真正的id士聪。
這里為什么用":"來(lái)作為分隔符我也不是很清楚...而且還學(xué)到一個(gè)東西ContentResolver.query()方法中selection參數(shù)可以不用占位符"?"直接獲取指定想要的列。
MediaStore.Images.Media._ID指的是我們獲取到指定image文件的id在表中的列名猛蔽。MediaStore.Images.Media.EXTERNAL_CONTENT_URI則是相冊(cè)圖片表真正的標(biāo)示符剥悟。
這里的Uri獲取是通過(guò)打開相冊(cè)選定圖片后,返回的Intent中獲取的曼库。
當(dāng)我們獲取到選中圖片真正的Uri后区岗,就可以通過(guò)之前的getImagePath()
方法來(lái)獲取表中的文件路徑。最終達(dá)到解碼圖片的目的毁枯。
實(shí)際效果
參考
Android 4.4從圖庫(kù)選擇圖片,獲取圖片路徑并裁剪
《第一行代碼》