【Android】安卓Q适配指南-相册

碎碎念

本来每次安卓版本升级都是非常期待的事情,但是开发者就吃苦了!!!

尤其是从Q开始,应用采用沙盒模式,即各种公共文件的访问都会受到限制。。。

所以适配Q成了当务之急,然鹅网上关于适配的资料少之又少(可能是我太菜了)

主要出现的问题:

根据图片的绝对路径无法正常加载图片,同时使用File.delete删除也是失效

直到我看到oppo开发者平台的开发指南:Android Q版本应用兼容性适配指导,才解决了这个问题!

特此记录一下。

权限申请(都是权限惹的祸)

安卓6.0以上动态申请权限,这里就写简单一点:

    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

动态申请:

 private void checkPermission() {
        int readExternalStoragePermissionResult = checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE);
        if(readExternalStoragePermissionResult != PackageManager.PERMISSION_GRANTED) {
            requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},1);
        }
    }

遍历图片

这里仍然使用ContentProvider来进行图片的获取。

首先我们要确定我们需要的内容,大概是图片路径、图片显示名称、图片ID、图片创建时间。

创建相应的Bean类:

public class PhotoBean {
    private String path;
    private String name;
    private int ID;
    private long createDate;


    public int getID() {
        return ID;
    }

    public void setID(int ID) {
        this.ID = ID;
    }

    public String getPath() {
        return path;
    }

    public void setPath(String path) {
        this.path = path;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public long getCreateDate() {
        return createDate;
    }

    public void setCreateDate(long createDate) {
        this.createDate = createDate;
    }

}

遍历图片:

 private List<PhotoBean> mPics = new ArrayList<>();

private void initData(){
        mPics.clear();
        ContentResolver contentResolver = getContentResolver();
        Uri uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
        Cursor query = contentResolver.query(uri,new String[]{
                MediaStore.Images.Media.DATA,
                MediaStore.Images.Media.DISPLAY_NAME,
                MediaStore.Images.Media.DATE_ADDED,
                MediaStore.Images.Media._ID},null,null,null,null);
        while(query.moveToNext()) {
            PhotoBean photoItem = new PhotoBean();
            photoItem.setPath(query.getString(0));
            //这里的下标跟上面的query第一个参数对应,时间是第2个,所以下标为1
            photoItem.setCreateDate(query.getLong(1));
            photoItem.setName(query.getString(2));
            photoItem.setID(query.getInt(query.getColumnIndex(MediaStore.MediaColumns._ID)));
            mPics.add(photoItem);
        }
        query.close();
    }

这样我们就取到了相册所有图片的信息,主要是查到这个ID

此时我们如果直接使用path来创建Bitmap去加载或者File、第三方框架均不能正确加载图片。

下面讲一下如何使用Uri来加载图片

获取Uri并加载图片

我们可以在PhotoBean中增加这个方法

 public Uri getUri(){
        Uri baseUri = Uri.parse("content://media/external/images/media");
        return Uri.withAppendedPath(baseUri, "" + ID);
    }

如果没有获取ID,只有photpath也是可以的,但影响效率:需要根据path再去查一遍

public static Uri getImageContentUri(Context context, String path) {
        Cursor cursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                new String[] { MediaStore.Images.Media._ID }, MediaStore.Images.Media.DATA + "=? ",
                new String[] { path }, 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 (new File(path).exists()) {
                ContentValues values = new ContentValues();
                values.put(MediaStore.Images.Media.DATA, path);
                return context.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
            } else {
                return null;
            }
        }
    }

拿到Uri以后就可以直接使用

 Glide.with(context).load(photoBeanList.get(position).getUri()).into(imageView);

这样就没有问题了。

图片删除操作

以前我们在删除的时候,需要开发者自己添加一个确认删除的功能,现在谷歌已经帮我们完成了。

File.delete也就失效了,相对来说比较安全吧。

同样的,我们需要使用Uri来进行操作。

 @TargetApi(29)
    public void deleteUri(Uri imageUri) {
        ContentResolver resolver = getContentResolver();
        OutputStream os = null;
        try {
            if (imageUri != null) {
               resolver.delete(imageUri,null,null);
            }
        } catch (RecoverableSecurityException e1) {
            Log.d(TAG,"get RecoverableSecurityException");
            try {
                this.startIntentSenderForResult(
                        e1.getUserAction().getActionIntent().getIntentSender(),
                        100, null, 0, 0, 0);
            } catch (IntentSender.SendIntentException e2) {
                Log.d(TAG,"startIntentSender fail");
            }
        }
    }

RecoverableSecurityException在谷歌文档中是这样解释的:This exception is only appropriate where there is a concrete action the user can take to recover and make forward progress, such as confirming or entering authentication credentials, or granting access.即对于图片的修改、删除操作都需要用户的允许,即也是一种权限,故需要抛出该异常并去申请获得该权限。

如图所示:

【Android】安卓Q适配指南-相册

啊,自己好菜_(¦3」∠)_

觉得文章好的欢迎点赞哦~

 

【Android】安卓Q适配指南-相册

上一篇:Event Handling Guide for iOS(五)


下一篇:Android studio 断点调试整理