Android4.4之后以及7.0访问相册和裁剪相关问题

Android4.4之后

我们知道,android4.4以后,如果以下代码直接访问系统图库

Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");

得到的Uri不再是content://media/类型的Uri,而是conten://…provider/类型的Uri。

Android4.4之前返回的格式

可以看到以往的返回Uri是这样

可以看到以往的返回Uri是这样

Android4.4之后返回格式

我们看到,格式已经不一样了。如果我们还想以往一样直接访问这个Uri后裁剪再存回这个Uri,app则会崩溃。网上已经有很多解决办法,这里就不再多说了,原因是我不推荐在4.4以后使用这个方法获取图片Uri,等下说说为什么

我们看到,格式已经不一样了。如果我们还想以往一样直接访问这个Uri后裁剪再存回这个Uri,app则会崩溃。网上已经有很多解决办法,这里就不再多说了,原因是我不推荐在4.4以后使用这个方法获取图片Uri,等下说说为什么

原因

其实4.4以后使用以上方式访问得到的Uri也有可能是以往的content://media/类型的,比如魅族MX5的5.1系统,所以如果我们要获得图片的真实路径,我们需要在api版本大于等于19时进行判断,采用不同的方法。而如果使用下面这种访问方式,则在7.0之前,只会返回content://media/类型Uri。

Intent intent = new Intent(Intent.ACTION_PICK); 
intent.setDat(MediaStore.Images.Media.EXTERNAL_CONTENT_URI);

如果是content://media/的Uri,那么我们就可以采用以下方式获取真实路径

public String changeToPath(Uri uri){
        String[] proj = { MediaStore.Images.Media.DATA };
        //sdk<=11,cursor = manageQuery(uri,proj,null,null,null)
        CursorLoader loader = new CursorLoader(this,uri,proj,null,null,null);
        Cursor cursor = loader.loadInBackground();
        int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
        cursor.moveToFirst();
        Log.w("changtoUri",cursor.getString(column_index));
        return cursor.getString(column_index);
    }

那么7.0以后呢?还有为什么不采用第一 种的访问图库的方法?


因为如果是7.0 以后,虽然ACTION_PICK返回的Uri不再是content://media/类型的Uri,但是我们依然可以使用上面提到的changToPath这种方法获取真实路径,而不必去根据不同Uri使用不同方法。那么7.0ACTION_PICK返回的Uri怎么样的呢?是这样的

这里写图片描述
图片不清晰,大概是这种类型的

content://com.google.android.apps.photos.contentprovider/-1/1/content://media/external/file/95/ORIGINAL/NONE/998221584 typ=image/* (has extras)

而对于第一种方法,是要使用不同的方法获取的,网上也有很多例子。

还有一个问题

就是app崩溃的问题,经过我的验证发现,我们在的7.0之前,访问图库是不能用,储存进去的uri一般而言都是content://meida/类Uri和file://类Uri(即Uri.fromFile(file)),所以当我们访问采用第一种方法访问到图片后调用Intent.getData()得到的content://…provider是无法写入裁剪后的图片的,所以这也是推荐使用第二方法的原因,在7.0之前,返回都是conten://media/类的Uri,如果7.0是provider类的,只要使用上面的changToPath()转化为真实路径再使用

File file = new File(changeToUrl(data.getData()));
 intent.putExtra(MediaStore.EXTRA_OUTPUT,Uri.fromFile(file));

就ok啦。当然也可以使用第一种方法针对不同的返回结果,只是我觉得麻烦了点。

再说7.0

6.0多了动态权限的管理,而7.0则直接认为Uri.fromFile(file)这个是不安全的,如果直接使用会抛出异常。那怎么办,使用FileProvider。网上也有很多例子,步骤我大概展示一下
1.在AndroidManifest.xml中注册我们的provider
2.在res/xml/目录下新建一个paths.xml,名字随意
3.在代码中使用FileProvider.getUriForFile()

这里写图片描述

这里写图片描述

这里写图片描述

如果data.getDtat()的uri是provider类的,回直接崩溃,如果是7.0的,则可以裁剪,但是当裁剪完存回去的时候,又崩溃了,要想存回去,intent3.putExtra(MediaStore.EXTRA_OUTPUT,uri) 这个uri只能是Uri.fromFile(file)类的fileUri,甚至不能是以前可以用的content://media/类的所以!在7.0,我们调用相机拍照就很麻烦了,过程如下 :


1.利用FileProvider获得一个uri用来储存拍好的图
2.调用系统裁剪功能,即

Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndtype(uri,"image/*")
intent.putExtra(MediaStore.EXTRA_OUTPUT,Uri.fromFile)
intent3.putExtra(MediaStore.EXTRA_OUTPUT,mUri)

注意,此时uri不能是我们FileProvider.getUriForFile()获得的,这个是自定义的privider类的Uri,是无法访问的,而选取图库返回的是只可读的,在4.4以后都一样,但是不能是自定义FilerProvider的uri,所以我们需要把uri变一下,可以使用如下方法转化为content://media/类的,这个是我在网上搜集到的

 public Uri getImageContentUri(Context context, File imageFile) {
        String filePath = imageFile.getAbsolutePath();
        Cursor cursor = context.getContentResolver().query(
                MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                new String[] { MediaStore.Images.Media._ID },
                MediaStore.Images.Media.DATA + "=? ",
                new String[] { filePath }, null);

        if (cursor != null && cursor.moveToFirst()) {
            int id = cursor.getInt(cursor
                    .getColumnIndex(MediaStore.MediaColumns._ID));
            Uri baseUri = Uri.parse("content://media/external/images/media");
            return Uri.withAppendedPath(baseUri, "" + id);
        } else {
            if (imageFile.exists()) {
                ContentValues values = new ContentValues();
                values.put(MediaStore.Images.Media.DATA, filePath);
                return context.getContentResolver().insert(
                        MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
            } else {
                return null;
            }
        }
    }

转换完成访问到之后,依然需要putExtra(… , uri)里面的uri改为file://类的即Uri.fromFile(file),因此我们可以调用上面的changToPath()把我们刚刚利用getImageContenturi()得到的content://media/类转为真实路径,再得到file,在得到file类uri,这样就可以把拍完裁剪完的图片存回去啦!

猜你喜欢

转载自blog.csdn.net/sinat_33878878/article/details/76467842