解决安卓7.0拍照,相册选择崩溃的问题(包括压缩图片在内)
2017-07-26 17:39
579 查看
在今天,项目的功能开发的告一段落了,回顾之前遇到的难题,觉得有必要在博客中记录一下,也方便下次自己能快速解决问题,同时,也能给遇到同样问题的人一个参考。
这问题就是当用户使用android 7.0系统的手机进行拍照的时候,崩溃的问题。崩溃的原因,网上有很多详细的介绍,参考官方文档对该错误的解释,是由于出于安全考虑,Android 7.0[API24]以及以上版本不支持file://,类型的uri,而是使用content://URI。不然会报
现在直接说明解决额步骤吧。
1.在清单文件AndroidManifest.xml中建一个内提供者
2.在res文件夹下面新建一个xml文件夹,然后在xml文件夹下面建立一个file_paths的xml文件作为provider的共享文件路径
其中name:一个引用字符串,意思就是可以随便写。
path:文件夹“相对路径”,完整路径取决于当前的标签类型。
path可以为空,表示指定目录下的所有文件、文件夹都可以被共享。
在这个文件中,为每个目录添加一个XML元素指定目录。paths 可以添加多个子路径:< files-path> 分享app内部的存储;< external-path> 分享外部的存储;< cache-path> 分享内部缓存目录。
< files-path >
代表目录为:Context.getFilesDir()
代表目录为:Environment.getExternalStorageDirectory()
代表目录为:getCacheDir()
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
如果对于path不理解的可以查询资料。
3.在代码中将原来的方法做判断,新增7.0的适配方法
拍照
从相册中选择
然后在onactivityresult拍照回调中
相册相关
然后在去获取相片信息那里
工具类
这问题就是当用户使用android 7.0系统的手机进行拍照的时候,崩溃的问题。崩溃的原因,网上有很多详细的介绍,参考官方文档对该错误的解释,是由于出于安全考虑,Android 7.0[API24]以及以上版本不支持file://,类型的uri,而是使用content://URI。不然会报
android.os.FileUriExposedException这个错误提示
现在直接说明解决额步骤吧。
1.在清单文件AndroidManifest.xml中建一个内提供者
<!-- 适配android 7.0 拍照闪退的处理 ,其中authorities的值要和等下代码中使用的一致就行,其中resource内的文件就是拍照后的共享文件 --> <provider android:name="android.support.v4.content.FileProvider" android:authorities="com.chc.photo.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider>
2.在res文件夹下面新建一个xml文件夹,然后在xml文件夹下面建立一个file_paths的xml文件作为provider的共享文件路径
<?xml version="1.0" encoding="utf-8"?> <resources xmlns:android="http://schemas.android.com/apk/res/android"> <paths> <external-path path="" name="camera_photos" /> <files-path path="" name="photos" /> </paths> </resources>
其中name:一个引用字符串,意思就是可以随便写。
path:文件夹“相对路径”,完整路径取决于当前的标签类型。
path可以为空,表示指定目录下的所有文件、文件夹都可以被共享。
在这个文件中,为每个目录添加一个XML元素指定目录。paths 可以添加多个子路径:< files-path> 分享app内部的存储;< external-path> 分享外部的存储;< cache-path> 分享内部缓存目录。
< files-path >
代表目录为:Context.getFilesDir()
代表目录为:Environment.getExternalStorageDirectory()
代表目录为:getCacheDir()
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
如果对于path不理解的可以查询资料。
3.在代码中将原来的方法做判断,新增7.0的适配方法
拍照
Intent camera = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); //适配android7.0 手机拍照取uri的处理 if(Build.VERSION.SDK_INT<24){ uri = Uri.fromFile(imgFile);//7.0这里会闪退,imgfile是图片文件路径 camera.putExtra(MediaStore.EXTRA_OUTPUT, uri); }else{ uri=FileProvider.getUriForFile(SellerAffiliate.this,"com.chc.photo.fileprovider",imgFile); camera.putExtra(MediaStore.EXTRA_OUTPUT, uri); camera.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION );//添加这一句表示对目标应用临时授权该Uri所代表的文件 } startActivityForResult(camera, FLAG_CHOOSE_CAMERA);
从相册中选择
getPhotoType="1"; intent = new Intent(); intent.setAction(Intent.ACTION_PICK); intent.setType("image/*"); startActivityForResult(intent, FLAG_CHOOSE_IMG);
然后在onactivityresult拍照回调中
/*******************拍照相关*********************/ else if (requestCode == FLAG_CHOOSE_CAMERA && resultCode == RESULT_OK) { Intent intent = new Intent(this, ActivityPhoto.class);//只是一个图片预览 if(uri.getScheme()!=null && "content".equalsIgnoreCase(uri.getScheme())){ intent.putExtra("path", imgFile.getAbsolutePath()); }else{ intent.putExtra("path", uri.getPath()); }
相册相关
if (requestCode == FLAG_CHOOSE_IMG && resultCode == RESULT_OK) { if (data != null) { Uri uri = data.getData(); String imgpath=BitmapComPressUtils.getRealFilePath(SellerAffiliate.this,uri); pathStr=imgpath; Intent intent = new Intent(this, ActivityPhoto.class); intent.putExtra("path", imgpath); startActivityForResult(intent, FLAG_MODIFY_FINISH); }
然后在去获取相片信息那里
if (data != null) { String filepath=""; //拍照返回 if(getPhotoType.equals("0")){ if(uri.getScheme()!=null && "content".equalsIgnoreCase(uri.getScheme())){ filepath=imgFile.getAbsolutePath(); }else{ filepath=uri.getPath(); } }//相册返回 else{ if (data != null) { filepath =pathStr; } } // pathStr=path; //将图片进行双重压缩后再上传 // String filepath=BitmapComPressUtils.getRealFilePath(SellerAffiliate.this,uri); Bitmap imgBitmap= BitmapComPressUtils.getDecordeImage(SellerAffiliate.this,filepath,800f,480f); if(imgBitmap==null){ return; } String imgpath=BitmapComPressUtils.saveBitmap(SellerAffiliate.this,imgBitmap); pathStr=imgpath;
工具类
/** * Created by chc on 2017/6/8/008. * 将图片先按照比例缩放,然后再进行质量压缩 * * */ public class BitmapComPressUtils { private Context context; public BitmapComPressUtils(){ } /** * 图片按比例大小压缩(用于二维码) * * @param srcPath * @return */ public static Bitmap getDecordeImage(Context context, String srcPath,float phoneHeight,float phoneWinth) { if (srcPath == null) { return null; } File file = new File(srcPath); if (!file.exists()) { return null; } BitmapFactory.Options newOpts = new BitmapFactory.Options(); // 开始读入图片,此时把options.inJustDecodeBounds 设回true了 newOpts.inJustDecodeBounds = true; Bitmap bitmap = BitmapFactory.decodeFile(srcPath, newOpts);// 此时返回bm为空 newOpts.inJustDecodeBounds = false; int w = newOpts.outWidth; int h = newOpts.outHeight; //横屏拍的 if((w/h)>1){ int temp=w; w=h; h=temp; } // 设置手机的宽高 float hh = phoneHeight;// 这里设置高度 float ww = phoneWinth;// 这里设置宽度 // float hh = 800f;// 这里设置高度 // float ww = 480f;// 这里设置宽度 // 缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可 int be = 1;// be=1表示不缩放 if (w > h && w > ww) {// 如果宽度大的话根据宽度固定大小缩放 be = (int) (newOpts.outWidth / ww); } else if (w < h && h > hh) {// 如果高度高的话根据宽度固定大小缩放 be = (int) (newOpts.outHeight / hh); } if (be <= 0) be = 1; newOpts.inSampleSize = be;// 设置缩放比例 // 重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了 bitmap = BitmapFactory.decodeFile(srcPath, newOpts); // if(Build.VERSION.SDK_INT>=24){ // try { // bitmap = BitmapFactory.decodeStream(context.getContentResolver().openInputStream(Uri.parse(srcPath))); // } catch (FileNotFoundException e) { // e.printStackTrace(); // } // }else{ // bitmap = BitmapFactory.decodeFile(srcPath, newOpts); // } return compressImage(bitmap);// 压缩好比例大小后再进行质量压缩 } public static Bitmap compressImage(Bitmap image) { if(image==null){ return null; } ByteArrayOutputStream baos = new ByteArrayOutputStream(); image.compress(Bitmap.CompressFormat.JPEG, 100, baos);//质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中 int options = 100; while ( baos.toByteArray().length / 1024>700) { //循环判断如果压缩后图片是 否大于700k,大于继续压缩 baos.reset();//重置baos即清空baos image.compress(Bitmap.CompressFormat.JPEG, options, baos);//这里压缩options%,把压缩后的数据存放到baos中 options -= 10;//每次都减少10 } ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());//把压缩后的数据baos存放到ByteArrayInputStream中 Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);//把ByteArrayInputStream数据生成图片 return bitmap; } //保存图片,返回路径 public static String saveBitmap(Context context,Bitmap bitmap) { String timeStamp = new SimpleDateFormat("yyyyMMddHHmmss") .format(new Date()); String origFileName = "osc_" + timeStamp + ".jpg"; File f = new File(CacheUtils.getCacheDirectory(context, true, "icon") + origFileName); if (f.exists()) { f.delete(); } try { FileOutputStream out = new FileOutputStream(f); bitmap.compress(Bitmap.CompressFormat.PNG, 100, out); out.flush(); out.close(); ProjectUrils.L.e("f.getpath"+f.getPath()); ProjectUrils.L.e("f.getAbsolutePath()"+f.getAbsolutePath()); ProjectUrils.L.e("f.getCanonicalPath()"+f.getCanonicalPath()); return f.getPath(); } catch (FileNotFoundException e) { e.printStackTrace(); return null; } catch (IOException e) { e.printStackTrace(); return null; } } /*******************android 7.0 URi崩溃,获取uri api 19以上***************************/ @TargetApi(19) public static String getImagePathHeight(Uri data,Context context){ if(data==null){ return null; } Uri imageUri=null; String imagePath = null; imageUri = data; if (DocumentsContract.isDocumentUri(context, imageUri)) { //如果是document类型的uri,则通过document id处理 String docId = DocumentsContract.getDocumentId(imageUri); if ("com.android.providers.media.documents".equals(imageUri.getAuthority())) { String id = docId.split(":")[1];//解析出数字格式的id String selection = MediaStore.Images.Media._ID + "=" + id; imagePath = getRealImagePaht(context,MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection); } else if ("com.android.downloads.documents".equals(imageUri.getAuthority())) { Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(docId)); imagePath = getRealImagePaht(context,contentUri, null); } } else if ("content".equalsIgnoreCase(imageUri.getScheme())) { //如果是content类型的Uri,则使用普通方式处理 imagePath = getRealImagePaht(context,imageUri, null); } else if ("file".equalsIgnoreCase(imageUri.getScheme())) { //如果是file类型的Uri,直接获取图片路径即可 imagePath = imageUri.getPath(); } return imagePath; } public static String getRealImagePaht(Context context,Uri uri, String selection) { String path = null; //通过Uri和selection老获取真实的图片路径 Cursor cursor = context.getContentResolver().query(uri, null, selection, null, null); if (cursor != null) { if (!cursor.isAfterLast()) { path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA)); cursor.moveToNext(); } cursor.close(); } return path; } public static String getRealFilePath( final Context context, final Uri uri ) { if ( null == uri ) return null; final String scheme = uri.getScheme(); String data = null; if ( scheme == null ) data = uri.getPath(); else if ( ContentResolver.SCHEME_FILE.equals( scheme ) ) { data = uri.getPath(); } else if ( ContentResolver.SCHEME_CONTENT.equals( scheme ) ) { Cursor cursor = context.getContentResolver().query( uri, new String[] { MediaStore.Images.ImageColumns.DATA }, null, null, null ); if ( null != cursor ) { if ( cursor.moveToFirst() ) { int index = cursor.getColumnIndex( MediaStore.Images.ImageColumns.DATA ); if ( index > -1 ) { data = cursor.getString( index ); } } cursor.close(); } } return data; } }
相关文章推荐
- Android拍照和从相册获取图片(解决android7.0打开相机崩溃的问题),同时也解决了拍完照后图片方向不正的问题
- Android拍照和从相册获取图片(解决android7.0打开相机崩溃的问题),同时也解决了拍完照后图片方向不正的问题
- Android拍照调用系统相册仿微信封装总结,治疗各种崩溃,图片横竖问题压缩等问题。-更新2016-12-21
- Android拍照调用系统相册仿微信封装总结,治疗各种崩溃,图片横竖问题压缩等问题。
- 解决调用系统拍照保存的图片被压缩的问题
- 完美解决三星手机拍照后横竖屏切换导致的回调为null以致程序崩溃的问题(包括三星note3的特殊适配)
- vue2移动端上传,预览,压缩图片,解决拍照旋转问题
- Android 图片选择和拍照(剪辑)及压缩问题
- MUI 单图片压缩上传(拍照+系统相册): 选择立即上传
- 选择相册中的图片,并获取图片的path 解决codova 华为P6选取相册的问题(试过很多,用此方案解决)
- 关于解决 从相册中选择照片后无法剪切图片以及无法加载图片的问题
- vue2实现移动端上传、预览、压缩图片解决拍照旋转问题
- 集成融云拍照,图片选择报错问题解决方案。
- TakePhoto是一款用于在Android设备上获取照片(拍照或从相册、文件中选择)、裁剪图片、压缩图片的开源工具库,目前最新版本3.0.0。
- Android开发——相册拍照_03.解决相机拍照之后部分手机无法将图片保存到路径或部分手机点击相机确定无法返回问题
- vue2移动端上传,预览,压缩图片,解决拍照旋转问题
- vue2移动端上传,预览,压缩图片,解决拍照旋转问题
- Fragment调用PopupWindow工具封装类开启拍照或相册选择图片后无法回调的解决办法!
- 兼容SDK4.4(api19)拍照、相册选择图片裁剪压缩上传头像
- Android 多媒体应用:从相册选择照片显示(解决相册中图片显示不出来的问题)