欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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

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

在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新版本发布时,会对现有应用产生什么影响,遇到问题多查看别人的解决办法,多归纳,多总结,这样才能使咱们的应用越来越完善。