android R (android 11 )(sdk 30 )上相册刷新问题

当你的机器Build.VERSION.SDK_INT > Build.VERSION_CODES.Q 的时候,你会发现刷新相册的方法不好使了,因为30的机器上,已经不允许直接发广播刷目录就在相册显示了,取而代之的是,他用了类似苹果那种,先向系统申请一个uri ,再进行拷贝写入的方法,步骤如下,

① 获取系统图片视频媒体的根Uri

需要用MediaStore.Video.Media去获取一个uri(图片的可以用MediaStore.Image.Media), 图片和视频的是分开的,额,好麻烦

val mediaUri = MediaStore.Video.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)

② 用这个uri向系统contentresolver中插入,获取一个属于你自己文件的uri
val localUri = resolver.insert(mediaUri, values)

这里的 values 就是你插入到系统媒体数据库中的contentvalue 键值对。contentValue 有两个重要的项MediaStore.Video.Media.RELATIVE_PATHMediaStore.MediaColumns.IS_PENDING

RELATIVE_PATH

这里有个潜规则,就是你通过MediaStore.Video.Media或者MediaStore.Image.Media拿到的这个uri,有权限的的目录只有三个, [DCIM, Movies, Pictures], 就是你手机根目录下的这三个文件夹, 指定其他目录会报异常, 如果不指定,视频默认到Movies 下,图片默认放到Pictures下。

是代表你存取的相对路径地址,相对那三个公共目录比如(Environment.DIRECTORY_DCIM +
File.separator + “你的目录”), 实际上就是前面提到的三个目录的字符串,如果你用不是这三个目录,马上报异常,

IS_PENDING

是否存取的时候独占 1 独占, 0非独占,因为这有一个io过程,这也提醒你,在高本版机器上,还是需要再io线程完成这个动作,

③通过这个uri, 拿到一个outputStream,向系统库写入。
resolver.openOutputStream(localUri)?.use { outputStream ->
                        val sink = outputStream.sink().buffer()
                        sink.writeAll(videoFile.source().buffer())
                        sink.flush()
                        values.clear()
                        values.put(MediaStore.Video.Media.IS_PENDING, 0)
                        resolver.update(localUri, values, null, null)
                    }

写入之完成之后,还可以resolver.update(localUri, values, null, null) ,你才可以在相册看到你存的东东 (比如微信里面的视频,写入完成后,就被写到三个目录中的Picture下的weixin 目录下了)

下面用的是okio,use是kotlin的扩展函数, 类似let,但是只能用在实现Closeable接口的对象上,默认好多io的都可以用,感觉更方便一些,等这些都弄完后,你才能看到视频出现在相册,好恶心。

低版本上还是可以用老办法,发广播


val resolver = context.contentResolver
            val values = getVideoContentValues(videoFile, System.currentTimeMillis())
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) {
                val mediaUri = MediaStore.Video.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
                val localUri = resolver.insert(mediaUri, values)
                localUri?.let {
                    resolver.openOutputStream(localUri)?.use { outputStream ->
                        val sink = outputStream.sink().buffer()
                        sink.writeAll(videoFile.source().buffer())
                        sink.flush()
                        values.clear()
                        values.put(MediaStore.Video.Media.IS_PENDING, 0)
                        resolver.update(localUri, values, null, null)
                    }
                }
            } 
fun getVideoContentValues(paramFile: File, currentTime: Long): ContentValues {
        val values = ContentValues()
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) {
            values.put(MediaStore.Video.Media.DATE_TAKEN, currentTime)
            values.put(
                MediaStore.Video.Media.RELATIVE_PATH,
                DirConstants.videoSaveRelativePath
            )
            values.put(MediaStore.MediaColumns.IS_PENDING, 1)
        } else {
            values.put(MediaStore.Video.Media.DATA, paramFile.absolutePath)
        }
        values.put(MediaStore.Video.Media.TITLE, paramFile.name)
        values.put(MediaStore.Video.Media.DISPLAY_NAME, paramFile.name)
        values.put(MediaStore.Video.Media.MIME_TYPE, "video/mp4")
        values.put(MediaStore.Video.Media.SIZE, paramFile.length())
        values.put(MediaStore.Video.Media.DATE_ADDED, currentTime)
        values.put(MediaStore.Video.Media.DATE_MODIFIED, currentTime)
        return values
    }
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值