首页 > 代码库 > 【原创】Android 4.4前后版本读取图库图片方式的变化

【原创】Android 4.4前后版本读取图库图片方式的变化

Android 4.4前后版本读取图库图片方式的变化

 
本文讲述Android 4.4(KitKat)前后访问图库以及访问后通过图片路径读取图片的变化
 

Android 4.4(KitKat)以前:

访问图库(方法一):
1      /**2      * Access the gallery to pick up an image. 3      */4      private   void  startPickPhotoActivity() {5         Intent intent =  new  Intent(Intent. ACTION_GET_CONTENT );6         intent.setType( "image/*" ); // Or ‘image/ jpeg ‘7         startActivityForResult(intent,  RESULT_PICK_PHOTO_NORMAL );8     }

访问图库(方法二):

1      /**2      * Access the gallery to pick up an image. 3      */4      private   void  startPickPhotoActivity() {5         Intent intent =  new  Intent(Intent. ACTION_GET_CONTENT );6         intent.setType( "image/*" ); // Or ‘image/ jpeg ‘7         Intent wrapperIntent = Intent. createChooser (intent,  null );8         startActivityForResult(wrapperIntent,  RESULT_PICK_PHOTO_NORMAL );9      }

 

获取文件路径&读取图片:
 1     @Override 2     protected void onActivityResult(int requestCode, int resultCode, Intent data) { 3         if (requestCode == RESULT_PICK_PHOTO_NORMAL) { 4             if (resultCode == RESULT_OK && data != null) { 5                 mFileName = DemoUtils.getDataColumn(getApplicationContext(), 6                         data.getData(), null, null); 7                 mColorBitmap = DemoUtils.getBitmap(mFileName); 8  9                 mImage.setImageBitmap(mColorBitmap);10             }11         }12     }13 14     public static final Bitmap getBitmap(String fileName) {15         Bitmap bitmap = null;16         try {17             Options options = new Options();18             options.inJustDecodeBounds = true;19             BitmapFactory.decodeFile(fileName, options);20             options.inSampleSize = Math.max(1, (int) Math.ceil(Math.max(21                     (double) options.outWidth / 1024f,22                     (double) options.outHeight / 1024f)));23             options.inJustDecodeBounds = false;24             bitmap = BitmapFactory.decodeFile(fileName, options);25         } catch (OutOfMemoryError error) {26             error.printStackTrace();27         }28 29         return bitmap;30     }31 32     /**33      * Get the value of the data column for this Uri . This is useful for34      * MediaStore Uris , and other file - based ContentProviders.35      * 36      * @param context37      *            The context.38      * @param uri39      *            The Uri to query.40      * @param selection41      *            (Optional) Filter used in the query.42      * @param selectionArgs43      *            (Optional) Selection arguments used in the query.44      * @return The value of the _data column, which is typically a file path.45      */46     public static String getDataColumn(Context context, Uri uri,47             String selection, String[] selectionArgs) {48         Cursor cursor = null;49         final String column = MediaColumns.DATA;50         final String[] projection = { column };51         try {52             cursor = context.getContentResolver().query(uri, projection,53                     selection, selectionArgs, null);54             if (cursor != null && cursor.moveToFirst()) {55                 final int index = cursor.getColumnIndexOrThrow(column);56                 return cursor.getString(index);57             }58         } finally {59             if (cursor != null)60                 cursor.close();61         }62         return null;63     }

 

Android 4.4(KitKat)及以后:

访问图库(方法一):同上方法一
访问图库(方法二):同上方法二
访问图库(方法三):
1      /**2      * Access the gallery to pick up an image. 3      */4      @TargetApi (Build.VERSION_CODES. KITKAT )5      private   void  startPickPhotoActivity() {6         Intent intent =  new  Intent(Intent. ACTION_OPEN_DOCUMENT );7         intent.setType( "image/*" ); // Or ‘image/ jpeg ‘8         startActivityForResult(intent,  RESULT_PICK_PHOTO_NORMAL );9     }

 

获取文件路径&读取图片:
  1     @Override  2     protected void onActivityResult(int requestCode, int resultCode, Intent data) {  3         if (requestCode == RESULT_PICK_PHOTO_KITKAT) {  4             if (resultCode == RESULT_OK && data != null) {  5                 mFileName = DemoUtils.getPath(getApplicationContext(),  6                         data.getData());  7                 mColorBitmap = DemoUtils.getBitmap(mFileName);  8   9                 mImage.setImageBitmap(mColorBitmap); 10             } 11         } 12     } 13  14     @TargetApi(Build.VERSION_CODES.KITKAT) 15     public static String getPath(final Context context, final Uri uri) { 16         final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT; 17         // DocumentProvider 18         if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) { 19             // ExternalStorageProvider 20             if (isExternalStorageDocument(uri)) { 21                 final String docId = DocumentsContract.getDocumentId(uri); 22                 final String[] split = docId.split(":"); 23                 final String type = split[0]; 24                 if ("primary".equalsIgnoreCase(type)) { 25                     return Environment.getExternalStorageDirectory() + "/" 26                             + split[1]; 27                 } 28                 // TODO handle non-primary volumes 29             } 30             // DownloadsProvider 31             else if (isDownloadsDocument(uri)) { 32                 final String id = DocumentsContract.getDocumentId(uri); 33                 final Uri contentUri = ContentUris.withAppendedId( 34                         Uri.parse("content://downloads/public_downloads"), 35                         Long.valueOf(id)); 36                 return getDataColumn(context, contentUri, null, null); 37             } 38             // MediaProvider 39             else if (isMediaDocument(uri)) { 40                 final String docId = DocumentsContract.getDocumentId(uri); 41                 final String[] split = docId.split(":"); 42                 final String type = split[0]; 43                 Uri contentUri = null; 44                 if ("image".equals(type)) { 45                     contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; 46                 } else if ("video".equals(type)) { 47                     contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; 48                 } else if ("audio".equals(type)) { 49                     contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; 50                 } 51                 final String selection = MediaColumns._ID + "=?"; 52                 final String[] selectionArgs = new String[] { split[1] }; 53                 return getDataColumn(context, contentUri, selection, 54                         selectionArgs); 55             } 56         } 57         // MediaStore (and general) 58         else if ("content".equalsIgnoreCase(uri.getScheme())) { 59             // Return the remote address 60             if (isGooglePhotosUri(uri)) 61                 return uri.getLastPathSegment(); 62             return getDataColumn(context, uri, null, null); 63         } 64         // File 65         else if ("file".equalsIgnoreCase(uri.getScheme())) { 66             return uri.getPath(); 67         } 68         return null; 69     } 70  71     /** 72      * Get the value of the data column for this Uri . This is useful for 73      * MediaStore Uris , and other file - based ContentProviders. 74      *  75      * @param context 76      *            The context. 77      * @param uri 78      *            The Uri to query. 79      * @param selection 80      *            (Optional) Filter used in the query. 81      * @param selectionArgs 82      *            (Optional) Selection arguments used in the query. 83      * @return The value of the _data column, which is typically a file path. 84      */ 85     public static String getDataColumn(Context context, Uri uri, 86             String selection, String[] selectionArgs) { 87         Cursor cursor = null; 88         final String column = MediaColumns.DATA; 89         final String[] projection = { column }; 90         try { 91             cursor = context.getContentResolver().query(uri, projection, 92                     selection, selectionArgs, null); 93             if (cursor != null && cursor.moveToFirst()) { 94                 final int index = cursor.getColumnIndexOrThrow(column); 95                 return cursor.getString(index); 96             } 97         } finally { 98             if (cursor != null) 99                 cursor.close();100         }101         return null;102     }103 104     /**105      * @param uri106      *            The Uri to check.107      * @return Whether the Uri authority is ExternalStorageProvider.108      */109     public static boolean isExternalStorageDocument(Uri uri) {110         return "com.android.externalstorage.documents".equals(uri111                 .getAuthority());112     }113 114     /**115      * @param uri116      *            The Uri to check.117      * @return Whether the Uri authority is DownloadsProvider.118      */119     public static boolean isDownloadsDocument(Uri uri) {120         return "com.android.providers.downloads.documents".equals(uri121                 .getAuthority());122     }123 124     /**125      * @param uri126      *            The Uri to check.127      * @return Whether the Uri authority is MediaProvider.128      */129     public static boolean isMediaDocument(Uri uri) {130         return "com.android.providers.media.documents".equals(uri131                 .getAuthority());132     }133 134     /**135      * @param uri136      *            The Uri to check.137      * @return Whether the Uri authority is Google Photos.138      */139     public static boolean isGooglePhotosUri(Uri uri) {140         return "com.google.android.apps.photos.content".equals(uri141                 .getAuthority());142     }

 

为什么会不一样呢?

Android 4.4(含)开始,通过方式访问图库后,返回的Uri如下(访问“最近”):
1 Uri is:         content://com.android.providers.media.documents/document/image%3A188382 Uri.getPath is :/document/image:188383 对应的图片真实路径:/storage/emulated/0/Pictures/Screenshots/Screenshot_2014-09-22-21-40-53.png

不但如此,对于不同类型图库,返回的Uri形式并不相同(访问普通相册):

1 Uri is:         content://media/external/images/media/188222 Uri.getPath is :/external/images/media/188223 对应的图片真实路径:/storage/emulated/0/Download/20130224235013.jpg

而4.4之前返回的Uri只存在一种形式,如下:

1 Uri is:         content://media/external/images/media/140462 Uri.getPath is :/external/images/media/140463 对应的图片真实路径:/storage/emulated/0/DCIM/Camera/20130224235013.jpg

 

因此,在Android 4.4或更高版本设备上,通过简单的getDataColumn(Context, Uri, null, null)进行图片数据库已经不能满足所有需求,因此在获取图片真实路径的时候需要根据不同类型区分对待。
 
其实,有一种更为Simple&Lazy的方式,就是通过数据库查询时指定图片id,更为精确的查询图片。
1 // TODO 从Uri中读取图片id,如:/document/image/18838,   /external/images/media/140462 // String id = ...3 // ......4  5 String selection = MediaColumns._ID + " = ?";6 String[] selectionArgs = new String{ id };7  8 Uri queryUri = "content://media/external/images/media";9 String fileName = getDataColumns(context, queryUri, selection, selectionArgs );

 

【原创】Android 4.4前后版本读取图库图片方式的变化