解决安卓7.0拍照,相册选择崩溃的问题(包括压缩图片在内)

在今天,项目的功能开发的告一段落了,回顾之前遇到的难题,觉得有必要在博客中记录一下,也方便下次自己能快速解决问题,同时,也能给遇到同样问题的人一个参考。
这问题就是当用户使用android 7.0系统的手机进行拍照的时候,崩溃的问题。崩溃的原因,网上有很多详细的介绍,参考官方文档对该错误的解释,是由于出于安全考虑,Android 7.0[API24]以及以上版本不支持file://,类型的uri,而是使用content://URI。不然会报

android.os.FileUriExposedException这个错误提示

现在直接说明解决额步骤吧。
1.在清单文件AndroidManifest.xml中建一个内提供者


        <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的共享文件路径


<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;
    }

    }

你可能感兴趣的:(V鸟)