三种方法,刷新 Android 的 MediaStore!让你保存的图片立即出现在相册里!

这样设计也很好理解,毕竟扫描全盘是非常的耗资源,所以系统肯定要把全盘扫描的权限拿在自己手里不开放出来,避免被第三方 App 滥用。

不过 Android 依然给我们提供了替代方案,那就是用 MediaScannerConnection 或者发送 ACTION_MEDIA_SCANNER_SCAN_FILE 广播。

接下来就来说说 ACTION_MEDIA_SCANNER_SCAN_FILE 这个广播。

3.2 使用广播刷新

通过广播刷新 MediaStore 的方式非常的简单,只需要指定文件路径和 Action 就好了。

val saveAs = “Your_Created_Image_File_Path”
val contentUri = Uri.fromFile(File(saveAs))
val mediaScanIntent = Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,contentUri)
sendBroadcast(mediaScanIntent)

正常情况下,它是没有问题的,不过假如你发现它不生效,就需要检查一下你文件的路径是否传递正确。

通过查看 MediaScannerReceiver 的源码,可以发现 onReceive() 方法中,针对 ACTION_MEDIA_SCANNER_SCAN_FILE 还有一个限制条件,那就是传递进去的文件绝对路径,必须是以 Environment.getExternalStorageDirectory() 方法的返回值开头。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

有兴趣可以仔细阅读源码,这里是 Android 6.0 的源码:

http://androidxref.com/6.0.0_r1/xref/packages/providers/MediaProvider/src/com/android/providers/media/MediaScannerReceiver.java

本质上,还是 /mnt/sdcard/ 路径就认,而 /sdcard/ 就无法使用,所以只要我们不硬编码文件路径,这个问题基本上也就不存在。

这里也提醒我们,一定不要在代码里,硬编码文件路径,算是一个编码规范了。

3.3 删除文件后刷新MediaStore

本文一直都在说添加新文件的时候,如何刷新 MediaStore 的问题。但是其实还涉及到另外一个问题,我们删除了一个已经被收录在 MediaStore 中的文件,怎么办?在本文里也顺便讲一下。

既然放在这一小节讲,首先想到的是,直接再发一个广播出去,刷新这个路径,但是查阅最终执行扫描前的 MediaScanner 的 scanSingleFile() 方法,你就会知道这样的方式是行不通的。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在这里可以看到,当你传递进去的文件路径,指向的文件不存在的时候,会直接 return 出去了,就执行不到刷新的逻辑里。

所幸的是,我在 DownloadManager 类中,找到了刷新删除文件的解决办法,依然是通过 ContentResolver 来解决。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这里通过 ContentResolver 来向 MediaStore 中发起一个删除文件的操作,只需要传递进去一个文件的绝对路径即可。

四、操作 MediaScannerConnection 类

4.1 使用 MediaScannerConnection

刷新 MediaStore 还有一个最通用也是我推荐的一个方法,那就是使用 MediaScannerConnection 进行操作。

不同于 MediaStore.Image.Media 和广播的方式,使用 MediaScannerConnection 不仅可以保存文件,还可以指定文件路径,最好的就是,它还支持刷新完成的回调。

如果我们对时序有要求,并且需要制定文件保存路径的话,最好的方式就是直接使用 MediaScannerConnection 类进行操作,并且这也应该是兼容最好的方式。

这里我们主要是利用 MediaScannerConnection 类的 scanFile() 方法进行触发扫描。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

通过 scanFile() 方法,我们只需要制定一个待刷新的文件路径和对应的 MimeType 即可,它支持传递多个路径,也可就是支持批量扫描。

注意这里的 MimeType 是一定要填写的,并且不能写通配符 */*null,否则会导致刷新失败,通常我们保存的是一个图片的话,只需要传递 image/jpeg 即可。

最后一个参数, onScanCompletedListener 中可以监听我们扫描的结果,需要注意的是,假如这里扫描的是多个文件路径,它也会被回调多次。所以如果有什么在刷新之后的后续操作,就需要特殊处理一下(原因后面是说)。

MediaScannerConnection.scanFile(this
, arrayOf(picFile.absolutePath)
, arrayOf(“image/jpeg”), { path, uri ->

Log.i(“cxmyDev”, "onScanCompleted : " + path)

})

scanFile() 方法的使用还是很简单的,没什么需要额外交代的了。

4.2 MediaScannerConnection 原理

依然是从源码中找答案,我们先来看看 scanFile() 方法的实现。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

scanFile() 里,创建了一个 MediaScannerConnection 并调用了 connect() 方法。接下来我们继续看 connect() 方法。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

connect() 方法中,可以看到,它实际上是 bindServer()MediaScannerService 这个系统服务,所有的操作都在 MediaScannerService 中。

MediaScannerService 的源码,有兴趣可以去这里查看:

http://androidxref.com/6.0.0_r1/xref/packages/providers/MediaProvider/src/com/android/providers/media/MediaScannerService.java

这是一个系统服务,我到这里就不继续跟下去了,回过头来继续看源码。

不过看到 connect() 方法的时候,那对应的,一定有 disconnect() 方法存在了,前面 bindService() 了一个系统服务,我们一定要有一个时机去调用 unbindService(),否则就会造成泄露。

MediaScannerConnection 确实提供了 disconnect() 方法,但是我们通过 scanFile() 方法拿不到这个对象。这里处理的非常的巧妙,不需要我们手动去触发 disconnect(),它是自维护的。

继续看 scanFile() 里被我们忽略的 ClientProxy 类,逻辑都在这里面。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

scanNextPath() 中,会去判断传递进去的文件路径是否都扫描过,如果已经没有更多需要扫描的路径了,就自己去调用 disconnect() 方法,回收资源。

到这里,也就解答了我们刚才的疑问,MediaScannerConnection 已经帮我们考虑了很多事情,我们只需要调用它的标准 API 就好了。

五、查缺补漏

5.1 扫描其他类型的媒体文件

在 Android 下,不仅仅只有图片,对于其他媒体文件,使用本文介绍的方法,也是适用的。

5.2 避免某个目录被 MediaStore 扫描

看完到这里应该会知道,哪怕我们什么都不做,在手机下次重启的时候,系统依然会去全盘扫描文件系统,更新 MediaStore。

但是有时候,我们有一些目录下的媒体文件,并不想让 MediaStore 扫描到,例如在 SDCard 上缓存的图片、图标等,这些我们都不想出现在系统相册内。

解决办法其实在官方文档中已经写了。

https://developer.android.com/guide/topics/data/data-storage.html

这里简单说一下,当不需要被 MediaStore 扫描的目录下,创建一个名为 .nomedia 的空文件,它将阻止媒体扫描程序读取这个目录下的媒体文件。也就无法通过 MediaStore 分享给其他程序。

最后

其实Android开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。

下面分享的腾讯、头条、阿里、美团、字节跳动等公司2019-2021年的高频面试题全套解析,博主还把这些技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,下面只是以图片的形式给大家展示一部分。

image

知识不体系?这里还有整理出来的Android进阶学习的思维脑图,给大家参考一个方向。

image

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

](https://bbs.csdn.net/topics/618156601)**

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 30
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值