原文章地址:Android 4.4從圖庫選擇圖片,獲取圖片路徑并裁剪
最近在做一個(gè)從圖庫選擇圖片或拍照,然后裁剪的功能.本來是沒問題的,一直在用
[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
01. Intent intent=new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
的方式來做,是調(diào)用系統(tǒng)圖庫來做,但是發(fā)現(xiàn)如果有圖片是同步到google相冊(cè)的話,圖庫里面能看到一個(gè)auto backup的目錄,點(diǎn)進(jìn)去選圖片的話是無法獲取到圖片的路徑的.因?yàn)槟切﹫D片根本就不存在于手機(jī)上.然后看到無論是百度貼吧,Instagram,或者還有些會(huì)選取圖片做修改的app,都是用一個(gè)很漂亮的圖片選擇器(4.4以上,4.3的還是用系統(tǒng)舊的圖庫).
而這個(gè)圖片選擇器可以屏蔽掉那個(gè)auto backup的目錄.所以就開始打算用這個(gè)圖片選擇器來選圖片了.
這個(gè)方法就是
[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
01. Intent intent=new Intent(Intent.ACTION_GET_CONTENT);//ACTION_OPEN_DOCUMENT
02. intent.addCategory(Intent.CATEGORY_OPENABLE);
03. intent.setType("image/jpeg");
04. if(android.os.Build.VERSION.SDK_INT>=android.os.Build.VERSION_CODES.KITKAT){
05.? ? ? ? startActivityForResult(intent, SELECT_PIC_KITKAT);
06. }else{
07.? ? ? ? startActivityForResult(intent, SELECT_PIC);
08. }
為什么要分開不同版本呢?其實(shí)在4.3或以下可以直接用ACTION_GET_CONTENT的,在4.4或以上,官方建議用ACTION_OPEN_DOCUMENT,但其實(shí)都不算太大區(qū)別,區(qū)別是他們返回的Uri,那個(gè)才叫大區(qū)別.這就是困擾了我一整天的問題所在了.
4.3或以下,選了圖片之后,根據(jù)Uri來做處理,很多帖子都有了,我就不詳細(xì)說了.主要是4.4,如果使用上面pick的原生方法來選圖,返回的uri還是正常的,但如果用ACTION_GET_CONTENT的方法,返回的uri跟4.3是完全不一樣的,4.3返回的是帶文件路徑的,而4.4返回的卻是content://com.Android.providers.media.documents/document/image:3951這樣的,沒有路徑,只有圖片編號(hào)的uri.這就導(dǎo)致接下來無法根據(jù)圖片路徑來裁剪的步驟了.
還好找了很多方法,包括加權(quán)限啊什么的,中間還試過用一些方法,自己的app沒崩潰,倒是讓系統(tǒng)圖庫崩潰了,引發(fā)了Java.lang.SecurityException.
[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
01. Caused by: java.lang.SecurityException: Permission Denial: opening provider com.android.providers.media.MediaDocumentsProvider from ProcessRecord{437b5d88 9494:com.google.android.gallery3d/u0a20} (pid=9494, uid=10020) requires android.permission.MANAGE_DOCUMENTS or android.permission.MANAGE_DOCUMENTS
看來4.4的系統(tǒng)還是有些bug.重點(diǎn)來了,4.4得到的uri,需要以下方法來獲取文件的路徑
[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
01. public static String getPath(final Context context, final Uri uri) {
02.
03.? ? final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
04.
05.? ? // DocumentProvider
06.? ? if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
07.? ? ? ? // ExternalStorageProvider
08.? ? ? ? if (isExternalStorageDocument(uri)) {
09.? ? ? ? ? ? final String docId = DocumentsContract.getDocumentId(uri);
10.? ? ? ? ? ? final String[] split = docId.split(":");
11.? ? ? ? ? ? final String type = split[0];
12.
13.? ? ? ? ? ? if ("primary".equalsIgnoreCase(type)) {
14.? ? ? ? ? ? ? ? return Environment.getExternalStorageDirectory() + "/" + split[1];
15.? ? ? ? ? ? }
16.
17.? ? ? ? ? ? // TODO handle non-primary volumes
18.? ? ? ? }
19.? ? ? ? // DownloadsProvider
20.? ? ? ? else if (isDownloadsDocument(uri)) {
21.
22.? ? ? ? ? ? final String id = DocumentsContract.getDocumentId(uri);
23.? ? ? ? ? ? final Uri contentUri = ContentUris.withAppendedId(
24.? ? ? ? ? ? ? ? ? ? Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
25.
26.? ? ? ? ? ? return getDataColumn(context, contentUri, null, null);
27.? ? ? ? }
28.? ? ? ? // MediaProvider
29.? ? ? ? else if (isMediaDocument(uri)) {
30.? ? ? ? ? ? final String docId = DocumentsContract.getDocumentId(uri);
31.? ? ? ? ? ? final String[] split = docId.split(":");
32.? ? ? ? ? ? final String type = split[0];
33.
34.? ? ? ? ? ? Uri contentUri = null;
35.? ? ? ? ? ? if ("image".equals(type)) {
36.? ? ? ? ? ? ? ? contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
37.? ? ? ? ? ? } else if ("video".equals(type)) {
38.? ? ? ? ? ? ? ? contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
39.? ? ? ? ? ? } else if ("audio".equals(type)) {
40.? ? ? ? ? ? ? ? contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
41.? ? ? ? ? ? }
42.
43.? ? ? ? ? ? final String selection = "_id=?";
44.? ? ? ? ? ? final String[] selectionArgs = new String[] {
45.? ? ? ? ? ? ? ? ? ? split[1]
46.? ? ? ? ? ? };
47.
48.? ? ? ? ? ? return getDataColumn(context, contentUri, selection, selectionArgs);
49.? ? ? ? }
50.? ? }
51.? ? // MediaStore (and general)
52.? ? else if ("content".equalsIgnoreCase(uri.getScheme())) {
53.
54.? ? ? ? // Return the remote address
55.? ? ? ? if (isGooglePhotosUri(uri))
56.? ? ? ? ? ? return uri.getLastPathSegment();
57.
58.? ? ? ? return getDataColumn(context, uri, null, null);
59.? ? }
60.? ? // File
61.? ? else if ("file".equalsIgnoreCase(uri.getScheme())) {
62.? ? ? ? return uri.getPath();
63.? ? }
64.
65.? ? return null;
66. }
67.
68. /**
69.? * Get the value of the data column for this Uri. This is useful for
70.? * MediaStore Uris, and other file-based ContentProviders.
71.? *
72.? * @param context The context.
73.? * @param uri The Uri to query.
74.? * @param selection (Optional) Filter used in the query.
75.? * @param selectionArgs (Optional) Selection arguments used in the query.
76.? * @return The value of the _data column, which is typically a file path.
77.? */
78. public static String getDataColumn(Context context, Uri uri, String selection,
79.? ? ? ? String[] selectionArgs) {
80.
81.? ? Cursor cursor = null;
82.? ? final String column = "_data";
83.? ? final String[] projection = {
84.? ? ? ? ? ? column
85.? ? };
86.
87.? ? try {
88.? ? ? ? cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
89.? ? ? ? ? ? ? ? null);
90.? ? ? ? if (cursor != null && cursor.moveToFirst()) {
91.? ? ? ? ? ? final int index = cursor.getColumnIndexOrThrow(column);
92.? ? ? ? ? ? return cursor.getString(index);
93.? ? ? ? }
94.? ? } finally {
95.? ? ? ? if (cursor != null)
96.? ? ? ? ? ? cursor.close();
97.? ? }
98.? ? return null;
99. }
100.
101.
102. /**
103.? * @param uri The Uri to check.
104.? * @return Whether the Uri authority is ExternalStorageProvider.
105.? */
106. public static boolean isExternalStorageDocument(Uri uri) {
107.? ? return "com.android.externalstorage.documents".equals(uri.getAuthority());
108. }
109.
110. /**
111.? * @param uri The Uri to check.
112.? * @return Whether the Uri authority is DownloadsProvider.
113.? */
114. public static boolean isDownloadsDocument(Uri uri) {
115.? ? return "com.android.providers.downloads.documents".equals(uri.getAuthority());
116. }
117.
118. /**
119.? * @param uri The Uri to check.
120.? * @return Whether the Uri authority is MediaProvider.
121.? */
122. public static boolean isMediaDocument(Uri uri) {
123.? ? return "com.android.providers.media.documents".equals(uri.getAuthority());
124. }
125.
126. /**
127.? * @param uri The Uri to check.
128.? * @return Whether the Uri authority is Google Photos.
129.? */
130. public static boolean isGooglePhotosUri(Uri uri) {
131.? ? return "com.google.android.apps.photos.content".equals(uri.getAuthority());
132. }
這樣,就可以在4.4上用漂亮的圖片選擇器,選到我們想要的文件,又不會(huì)出問題了.
昨天發(fā)現(xiàn)了個(gè)bug,如果在4.4上面不用"圖片"來選,用"圖庫"來選,就會(huì)無法讀取到圖片路徑,所以只需要加個(gè)判斷,如果是用舊方式來選,就用舊方式來讀,就是如果
DocumentsContract.isDocumentUri(context, uri) 返回false的話,就用舊的方式
[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
01. public static String selectImage(Context context,Intent data){
02.? ? ? ? Uri selectedImage = data.getData();
03. //? ? ? Log.e(TAG, selectedImage.toString());
04.? ? ? ? if(selectedImage!=null){
05.? ? ? ? ? ? String uriStr=selectedImage.toString();
06.? ? ? ? ? ? String path=uriStr.substring(10,uriStr.length());
07.? ? ? ? ? ? if(path.startsWith("com.sec.android.gallery3d")){
08.? ? ? ? ? ? ? ? Log.e(TAG, "It's auto backup pic path:"+selectedImage.toString());
09.? ? ? ? ? ? ? ? return null;
10.? ? ? ? ? ? }
11.? ? ? ? }
12.? ? ? ? String[] filePathColumn = { MediaStore.Images.Media.DATA };
13.? ? ? ? Cursor cursor = context.getContentResolver().query(selectedImage,filePathColumn, null, null, null);
14.? ? ? ? cursor.moveToFirst();
15.? ? ? ? int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
16.? ? ? ? String picturePath = cursor.getString(columnIndex);
17.? ? ? ? cursor.close();
18.? ? ? ? return picturePath;
19.? ? }
這樣就OK的了