资讯专栏INFORMATION COLUMN

Android根据图片Uri获取图片path绝对路径的几种方法【转】

zzbo / 4654人阅读

摘要:然后再在中获取到图片的路径通用资源标志符简称,代表要操作的数据,上可用的每种资源如图像视频片段等都可以用来表示。

在Android 编程中经常会用到Uri转化为文件路径,如我们从相册选择图片上传至服务器,一般上传前需要对图片进行压缩,这时候就要用到图片的绝对路径。 
下面对我开发中uri转path路径遇到的问题进行总结,其中涉及到Android不同api下对于uri的处理,还有对于Google相册图片该如何获取其图片路径。

1. 从相册获取图片

我们从相册获取的图片的代码如下:

1 // 激活系统图库,选择一张图片
2 Intent intent = new Intent(Intent.ACTION_PICK);
3 intent.setType("image/*");
4 intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
5 startActivityForResult(intent, Constants.PHOTO_REQUEST_GALLERY);

当然针对Android 6.0以上系统还需要获取WRITE_EXTERNAL_STORAGE和READ_EXTERNAL_STORAGE操作手机sd卡权限才行。 
然后再在onActivityResult中获取到图片的uri路径:

 1 @Override
 2 public void onActivityResult(int requestCode, int resultCode, Intent data) {
 3         super.onActivityResult(requestCode, resultCode, data);
 4         if (resultCode == Activity.RESULT_OK) {
 5             switch (requestCode) {
 6                 case Constants.PHOTO_REQUEST_GALLERY:
 7                     Uri uri = data.getData();
 8                     break;
 9              }
10         }
11     }

Uri:通用资源标志符(Universal Resource Identifier, 简称”URI”),Uri代表要操作的数据,Android上可用的每种资源(如图像、视频片段等)都可以用Uri来表示。 
Uri一般由三部分组成:访问资源的命名机制。存放资源的主机名。资源自身的名称,由路径表示。

2.根据Uri获取path路径 2.1 Android 4.4以下获取图片路径
 1 /**
 2      * 获取小于api19时获取相册中图片真正的uri
 3      * 对于路径是:content://media/external/images/media/33517这种的,需要转成/storage/emulated/0/DCIM/Camera/IMG_20160807_133403.jpg路径,也是使用这种方法
 4      * @param context
 5      * @param uri
 6      * @return
 7      */
 8     public static String getFilePath_below19(Context context,Uri uri) {
 9         //这里开始的第二部分,获取图片的路径:低版本的是没问题的,但是sdk>19会获取不到
10         Cursor cursor = null;
11         String path = "";
12         try {
13             String[] proj = {MediaStore.Images.Media.DATA};
14             //好像是android多媒体数据库的封装接口,具体的看Android文档
15             cursor = context.getContentResolver().query(uri, proj, null, null, null);
16             //获得用户选择的图片的索引值
17             int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
18             //将光标移至开头 ,这个很重要,不小心很容易引起越界
19             cursor.moveToFirst();
20             //最后根据索引值获取图片路径   结果类似:/mnt/sdcard/DCIM/Camera/IMG_20151124_013332.jpg
21             path = cursor.getString(column_index);
22         } finally {
23             if (cursor != null) {
24                 cursor.close();
25             }
26         }
27         return path;
28     }
2.2.2 对于Android 4.4及以上机型获取path
  1 /**
  2      * @param context 上下文对象
  3      * @param uri     当前相册照片的Uri
  4      * @return 解析后的Uri对应的String
  5      */
  6     @SuppressLint("NewApi")
  7     public static String getPath(final Context context, final Uri uri) {
  8 
  9         final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
 10         String pathHead = "file:///";
 11         // 1. DocumentProvider
 12         if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
 13             // 1.1 ExternalStorageProvider
 14             if (isExternalStorageDocument(uri)) {
 15                 final String docId = DocumentsContract.getDocumentId(uri);
 16                 final String[] split = docId.split(":");
 17                 final String type = split[0];
 18                 if ("primary".equalsIgnoreCase(type)) {
 19                     return pathHead + Environment.getExternalStorageDirectory() + "/" + split[1];
 20                 }
 21             }
 22             // 1.2 DownloadsProvider
 23             else if (isDownloadsDocument(uri)) {
 24                 final String id = DocumentsContract.getDocumentId(uri);
 25                 final Uri contentUri = ContentUris.
 26                         withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
 27                 return pathHead + getDataColumn(context,
 28                         contentUri, null, null);
 29             }
 30             // 1.3 MediaProvider
 31             else if (isMediaDocument(uri)) {
 32                 final String docId = DocumentsContract.getDocumentId(uri);
 33                 final String[] split = docId.split(":");
 34                 final String type = split[0];
 35 
 36                 Uri contentUri = null;
 37                 if ("image".equals(type)) {
 38                     contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
 39                 } else if ("video".equals(type)) {
 40                     contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
 41                 } else if ("audio".equals(type)) {
 42                     contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
 43                 }
 44 
 45                 final String selection = "_id=?";
 46                 final String[] selectionArgs = new String[]{split[1]};
 47 
 48                 return pathHead + getDataColumn(context, contentUri, selection, selectionArgs);
 49             }
 50         }
 51         // 2. MediaStore (and general)
 52         else if ("content".equalsIgnoreCase(uri.getScheme())) {
 53             if (isGooglePhotosUri(uri)) {//判断是否是google相册图片
 54                 return uri.getLastPathSegment();
 55             } else if (isGooglePlayPhotosUri(uri)) {//判断是否是Google相册图片
 56                 return getImageUrlWithAuthority(context, uri);
 57             } else {//其他类似于media这样的图片,和android4.4以下获取图片path方法类似
 58                 return getFilePath_below19(context, uri);
 59             }
 60         }
 61         // 3. 判断是否是文件形式 File
 62         else if ("file".equalsIgnoreCase(uri.getScheme())) {
 63             return pathHead + uri.getPath();
 64         }
 65         return null;
 66     } 
 67 /**
 68      * @param uri
 69      *         The Uri to check.
 70      * @return Whether the Uri authority is ExternalStorageProvider.
 71      */
 72     private static boolean isExternalStorageDocument(Uri uri) {
 73         return "com.android.externalstorage.documents".equals(uri.getAuthority());
 74     }
 75 
 76     /**
 77      * @param uri
 78      *         The Uri to check.
 79      * @return Whether the Uri authority is DownloadsProvider.
 80      */
 81     private static boolean isDownloadsDocument(Uri uri) {
 82         return "com.android.providers.downloads.documents".equals(uri.getAuthority());
 83     }
 84 
 85     /**
 86      * @param uri
 87      *         The Uri to check.
 88      * @return Whether the Uri authority is MediaProvider.
 89      */
 90     private static boolean isMediaDocument(Uri uri) {
 91         return "com.android.providers.media.documents".equals(uri.getAuthority());
 92     }
 93 /**
 94  *  判断是否是Google相册的图片,类似于content://com.google.android.apps.photos.content/...
 95 **/
 96 public static boolean isGooglePhotosUri(Uri uri) {
 97          return "com.google.android.apps.photos.content".equals(uri.getAuthority());
 98     }
 99 
100 /**
101  *  判断是否是Google相册的图片,类似于content://com.google.android.apps.photos.contentprovider/0/1/mediakey:/local%3A821abd2f-9f8c-4931-bbe9-a975d1f5fabc/ORIGINAL/NONE/1075342619
102 **/
103 public static boolean isGooglePlayPhotosUri(Uri uri) {
104     return "com.google.android.apps.photos.contentprovider".equals(uri.getAuthority());
105 } 
2.2.3 针对Google相册图片获取方法

从相册中选择图片,如果手机安装了Google Photo,它的路径格式如下: 
content://com.google.android.apps.photos.contentprovider/0/1/mediakey%3A%2Flocal%253A821abd2f-9f8c-4931-bbe9-a975d1f5fabc/ORIGINAL/NONE/1754758324 
用原来的方式获取是不起作用的,path会是null,我们可以通过下面的形式获取:

 1 /**
 2  * Google相册图片获取路径
 3 **/
 4 public static String getImageUrlWithAuthority(Context context, Uri uri) {
 5         InputStream is = null;
 6         if (uri.getAuthority() != null) {
 7             try {
 8                 is = context.getContentResolver().openInputStream(uri);
 9                 Bitmap bmp = BitmapFactory.decodeStream(is);
10                 return writeToTempImageAndGetPathUri(context, bmp).toString();
11             } catch (FileNotFoundException e) {
12                 e.printStackTrace();
13             }finally {
14                 try {
15                     is.close();
16                 } catch (IOException e) {
17                     e.printStackTrace();
18                 }
19             }
20         }
21         return null;
22     }
23 /**
24  * 将图片流读取出来保存到手机本地相册中
25 **/
26 public static Uri writeToTempImageAndGetPathUri(Context inContext, Bitmap inImage) {
27     ByteArrayOutputStream bytes = new ByteArrayOutputStream();
28     inImage.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
29     String path = MediaStore.Images.Media.insertImage(inContext.getContentResolver(), inImage, "Title", null);
30     return Uri.parse(path);
31 }   

通过流的形式将图片读进来,转成bitmap形式,再写进手机媒体中,转换成路径如下:content://media/external/images/media/1754758324,因为Google中的图片并不在我们系统手机相册中,需要先下载,再转存。

3. 针对Android 7.0及以上机型打开Uri适配

Android7.0以上机型,若要在应用间共享文件,应发送一项 content:// URI,并授予 Uri临时访问权限。进行此授权的最简单方式是使用 FileProvider 类。如需了解有关权限和共享文件的详细信息,请参阅官方的共享文件。

具体需要在AndroidMainfest.xml文件中添加provider标签,并定义相应的路径,具体可参考鸿洋写的Android 7.0 行为变更 通过FileProvider在应用间共享文件吧 
具体裁剪图片代码如下

 1 /**
 2      * @param activity  当前activity
 3      * @param orgUri 剪裁原图的Uri
 4      * @param desUri 剪裁后的图片的Uri
 5      * @param aspectX X方向的比例
 6      * @param aspectY  Y方向的比例
 7      * @param width 剪裁图片的宽度
 8      * @param height 剪裁图片高度
 9      * @param requestCode  剪裁图片的请求码
10      */
11     public static void cropImageUri(Activity activity, Uri orgUri,
12                                     Uri desUri, int aspectX, int aspectY,
13                                     int width, int height, int requestCode) {
14         Intent intent = new Intent("com.android.camera.action.CROP");
15         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
16             intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
17             orgUri = FileProvider.getUriForFile(activity, "com.smilexie.storytree.fileprovider", new File(newUri.getPath()));
18         }
19         intent.setDataAndType(orgUri, "image/*");
20         intent.putExtra("crop", "true");
21         intent.putExtra("outputX", width);
22         intent.putExtra("outputY", height);
23         intent.putExtra("scale", true);
24         //将剪切的图片保存到目标Uri中
25         intent.putExtra(MediaStore.EXTRA_OUTPUT, desUri);
26         intent.putExtra("return-data", false);
27         intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
28         intent.putExtra("noFaceDetection", true);
29         activity.startActivityForResult(intent, requestCode);
30     }

只要是打开文件,uri都需要更改,不然解析异常,但是保存进uri则不需要修改。

总结

Android各版本,各机型适配不得不说有很多坑,比如我在开发中遇到google相册图片,老是获取不到路径。只能平时多关注Android新版本发布时,会对现有应用产生什么影响,遇到问题多查看别人的解决办法,多归纳,多总结,这样才能使咱们的应用越来越完善。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/2782.html

相关文章

  • Android Picasso最详细的使用指南

    摘要:比如高斯模糊,圆角圆形等处理。可以在一个请求上应用多个比如我想先做个度灰处理然后在做一个高斯模糊图第一步定义一个度灰的第二步如果是多个操作,有两种方式应用方式一直接调用多次方法,不会覆盖的。Picasso 是Square 公司开源的Android 端的图片加载和缓存框架。Square 真是一家良心公司啊,为我们Android开发者贡献了很多优秀的开源项目有木有!像什么Rerefoit 、Ok...

    pepperwang 评论0 收藏0
  • 判断浏览器是否支持 webp 几种解决方法

    摘要:实现方法方法二在服务端根据请求信息判断浏览器是否支持谷歌浏览器上请求图片是这样的浏览器请求图片是这样的在图片请求发出的时候,里有,服务端可以根据里面是否有进行判断。 我们都知道,WebP 是 Google 推出的 WebP 图片格式,它是一种支持有损压缩和无损压缩的图片文件格式,根据Google测试,相同的图片,WebP 格式的图片均能比 PNG,JPG 格式的图片节约不少体积,但是其...

    DobbyKim 评论0 收藏0
  • ReactNative开发笔记(持续更新...)

    摘要:,已过期,请使用代替。解决方案安卓增加属性并设置为官方解释当图片实际尺寸和容器样式尺寸不一致时,决定以怎样的策略来调整图片的尺寸。 本文均为RN开发过程中遇到的问题、坑点的分析及解决方案,各问题点之间无关联,希望能帮助读者少走弯路,持续更新中... (2019年3月29日更新) 原文链接:http://www.kovli.com/2018/06/... 作者:Kovli - 如何在原生...

    浠ラ箍 评论0 收藏0
  • Vue.js中引入图片路径几种方式

    摘要:记录总结一下的中引入图片路径的几种书写方式中静态资源的引入机制关于静态资源的官方文档静态资源可以通过两种方式进行处理在被导入或在中通过相对路径以开头被引用。如果是一个绝对路径,例如,它将会被保留不变。 vue --version 3.6.3记录总结一下的Vue中引入图片路径的几种书写方式 vue中静态资源的引入机制 Vue.js关于静态资源的官方文档 静态资源可以通过两种方式进行处理...

    adam1q84 评论0 收藏0
  • Android--解决图片保存到相册显示1970年1月1日 8:00的问题

    摘要:保存一张或者多张图片到图库不能为图片数组为保存图片到图库请在设置授予应用存储权限保存多张图片图片已成功保存到系统相册保存到相册获得路径内存卡不可用首先保存图片获取文件存储路径创建文件截取取出名字插入图库最后通知图库更新保存到相册获得路径不传import android.content.Context; import android.content.Intent; import android...

    muddyway 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<