Android根据图片Uri获取图片path绝对路径的几种方法【转】
在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新版本发布时,会对现有应用产生什么影响,遇到问题多查看别人的解决办法,多归纳,多总结,这样才能使咱们的应用越来越完善。
上一篇: react-fetch数据发送请求
下一篇: appium自动化环境搭建