转至 http://blog.csdn.net/tempersitu/article/details/20557383

最近在做一个从图库选择图片或拍照,然后裁剪的功能.本来是没问题的,一直在用

  1. Intent intent=new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);

的方式来做,是调用系统图库来做,但是发现如果有图片是同步到google相册的话,图库里面能看到一个auto backup的目录,点进去选图片的话是无法获取到图片的路径的.因为那些图片根本就不存在于手机上.然后看到无论是百度贴吧,Instagram,或者还有些会选取图片做修改的app,都是用一个很漂亮的图片选择器(4.4以上,4.3的还是用系统旧的图库).

而这个图片选择器可以屏蔽掉那个auto backup的目录.所以就开始打算用这个图片选择器来选图片了.
这个方法就是

  1. Intent intent=new Intent(Intent.ACTION_GET_CONTENT);//ACTION_OPEN_DOCUMENT
  2. intent.addCategory(Intent.CATEGORY_OPENABLE);
  3. intent.setType("image/jpeg");
  4. if(android.os.Build.VERSION.SDK_INT>=android.os.Build.VERSION_CODES.KITKAT){
  5. startActivityForResult(intent, SELECT_PIC_KITKAT);
  6. }else{
  7. startActivityForResult(intent, SELECT_PIC);
  8. }

为什么要分开不同版本呢?其实在4.3或以下可以直接用ACTION_GET_CONTENT的,在4.4或以上,官方建议用ACTION_OPEN_DOCUMENT,但其实都不算太大区别,区别是他们返回的Uri,那个才叫大区别.这就是困扰了我一整天的问题所在了.

4.3或以下,选了图片之后,根据Uri来做处理,很多帖子都有了,我就不详细说了.主要是4.4,如果使用上面pick的原生方法来选图,返回的uri还是正常的,但如果用ACTION_GET_CONTENT的方法,返回的uri跟4.3是完全不一样的,4.3返回的是带文件路径的,而4.4返回的却是content://com.android.providers.media.documents/document/image:3951这样的,没有路径,只有图片编号的uri.这就导致接下来无法根据图片路径来裁剪的步骤了.

还好找了很多方法,包括加权限啊什么的,中间还试过用一些方法,自己的app没崩溃,倒是让系统图库崩溃了,引发了java.lang.SecurityException.

  1. 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的系统还是有些bug.重点来了,4.4得到的uri,需要以下方法来获取文件的路径

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

这样,就可以在4.4上用漂亮的图片选择器,选到我们想要的文件,又不会出问题了.

昨天发现了个bug,如果在4.4上面不用"图片"来选,用"图库"来选,就会无法读取到图片路径,所以只需要加个判断,如果是用旧方式来选,就用旧方式来读,就是如果
DocumentsContract.isDocumentUri(context, uri) 返回false的话,就用旧的方式

  1. public static String selectImage(Context context,Intent data){
  2. Uri selectedImage = data.getData();
  3. //      Log.e(TAG, selectedImage.toString());
  4. if(selectedImage!=null){
  5. String uriStr=selectedImage.toString();
  6. String path=uriStr.substring(10,uriStr.length());
  7. if(path.startsWith("com.sec.android.gallery3d")){
  8. Log.e(TAG, "It's auto backup pic path:"+selectedImage.toString());
  9. 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的了

Android 4.4从图库选择图片,获取图片路径并裁剪的更多相关文章

  1. Android 从 Android 本地图库选择多个图片

    原文地址 本文说明如何从 Android 本地图库选择多个图片.作者考虑很多解决方案. 演示从 Android 本地图库选择多个图片,有两个方法可以实现从图库中选择多个图片: 用 Intent 获取多 ...

  2. android 拍照或者图库选择 压缩后 图片 上传

    通过拍照或者从相册里选择图片通过压缩并上传时很多应用的常用功能,记录一下实现过程 一:创建个临时文件夹用于保存压缩后需要上传的图片 /** * path:存放图片目录路径 */ private Str ...

  3. UIImagePickerController从拍照、图库、相册获取图片

    iOS 获取图片有三种方法: 1. 直接调用摄像头拍照 2. 从相册中选择 3. 从图库中选择 UIImagePickerController 是系统提供的用来获取图片和视频的接口: 用UIImage ...

  4. javascript加载图片获取图片尺寸信息方法

    如果你遇到不方便从服务器取图片尺寸信息的话,用下面代码就很方便了. // 更新: // 05.27: 1.保证回调执行顺序:error > ready > load:2.回调函数this指 ...

  5. Android笔记之从图库选择图片

    Demo链接:https://pan.baidu.com/s/1T4T2pTEswmbcYYfpN3OwDw,提取码:pzqy 参考链接:[Android Example] Pick Image fr ...

  6. Android拍照得到全尺寸图片并进行压缩/拍照或者图库选择 压缩后 图片 上传

    http://www.jb51.net/article/77223.htm https://www.cnblogs.com/breeze1988/p/4019510.html

  7. 前端模拟 图片上传---->>通过选取的图片获取其路径<<------

    <head> <meta charset="UTF-8"> <title>Title</title> <style> d ...

  8. Android系统拍照之后回显并且获取文件路径

    /*调用拍照返回*/ case PHOTO_REQUEST_GALLERY: if (data != null) { Uri uri = data.getData(); String photopat ...

  9. android 照相或从相册获取图片并裁剪

    照相或从相册获取图片并裁剪 在android应用中很多时候都要获取图片(例如获取用户的头像)就需要从用户手机上获取图片.可以直接照,也可以从用户SD卡上获取图片,但获取到的图片未必能达到要求.所以要对 ...

随机推荐

  1. idea 换主题

    换背景 . 选中行变色

  2. iOS开发:代码通用性以及其规范 第二篇(猜想iOS中实现TableView内部设计思路(附代码),以类似的思想实现一个通用的进度条)

    在iOS开发中,经常是要用到UITableView的,我曾经思考过这样一个问题,为什么任何种类的model放到TableView和所需的cell里面,都可以正常显示?而我自己写的很多view却只是能放 ...

  3. Android开发(三十)——ScrollView中ListView的高度自动适应

    int totalHeight = 0; for (int i = 0; i < mStrings.length; i++) { //pullList ListView //mAdapter A ...

  4. oracle的db link

    cd $ORACLE_HOME/network/admin vi tnsnames.ora 添加 CCPBS_19 =  (DESCRIPTION =    (ADDRESS_LIST =      ...

  5. Hydra扫描姿势

    参数详解: -R 根据上一次进度继续破解 -S 使用SSL协议连接 -s 指定端口 -l 指定用户名 -L 指定用户名字典(文件) -p 指定密码破解 -P 指定密码字典(文件) -e 空密码探测和指 ...

  6. 神奇的bug,退出时自动更新时间

    遇到一个神奇的bug,用户退出时,上次登录时间会变成退出时的时间. 于是开始跟踪,发现Laravel在退出时,会做一次脏检查,这时会更新rember_token,这时就会有update操作如下. 而粗 ...

  7. JAVA传入一个字符串,返回一个字符串中的大写字母

    /**      *       * @param 传入一个字符串      * @return 返回一个字符串中的大写字母      */     private static String str ...

  8. sparkonhbase

    import org.apache.hadoop.hbase.HBaseConfiguration import org.apache.hadoop.hbase.client.Result impor ...

  9. git的使用总结

    git使用技巧 git使用技巧 windows下git使用 git ignore file git 打tag vim编码设置 git ls显示中文乱码问题 git view history 查看某个文 ...

  10. Java new Date() bug

    往 MongoDB 中 upsert 记录,记录中的一个字段是 Date 类型的,这个字段是我 new Date() 放进去的. 然后落库的时候,发现这个时间比当前时间要晚 1h30min 左右. 我 ...