如何保存RecyclerView完整数据以避免重复扫描内部存储图片?
问题解答
关于RecyclerView.State的疑问
首先明确:官方文档中提到的arbitrary data不是指RecyclerView绑定的列表全量数据,它仅用于存储RecyclerView自身布局相关的临时状态(比如滚动位置、子项临时测量标记等),生命周期和当前RecyclerView实例完全绑定,进程销毁后数据就会丢失,完全不支持持久化存储,不能用来实现你要的跨启动恢复列表数据的需求。
列表数据持久化方案
你已经实现了任意对象的内部存储读写能力,直接持久化ArrayList<ImageModel>列表即可,这是最符合你场景的方案:
- 首次启动APP拉取完50张照片、首次调用
fetchImages拿到匹配的列表后,直接把该列表序列化存入内部存储 - 后续每次进入照片页面,优先读取本地缓存的列表,无需再遍历全量MediaStore扫描照片
额外优化建议:
- 这50张照片是你自己下载到extras文件夹的,完全可以在下载时就直接记录每张照片的Uri并存储,不需要走系统MediaStore查询逻辑,连首次的全量扫描耗时都能省去。
- 如果确实需要扫描MediaStore,可以给
query方法加selection参数,直接在系统层面过滤相册名称,不需要遍历所有图片再自己判断,扫描耗时会大幅降低:String selection = MediaStore.Images.Media.BUCKET_DISPLAY_NAME + " = ?"; String[] selectionArgs = new String[]{"extras"}; cursor = activity.getApplicationContext().getContentResolver().query(uri, projection, selection, selectionArgs, null);
解决加载丢帧/闪烁问题
你遇到的问题是加载时机和更新方式不对,可以按以下步骤优化:
- 禁止在主线程
onCreateView中直接读本地缓存,避免阻塞主线程丢帧 - 优化初始化逻辑:
- 页面初始化时,先给RecyclerView设置固定尺寸属性
recyclerView.setHasFixedSize(true),同时给列表item布局设置固定高度,减少列表测量耗时 - 提前初始化一次PhotosAdapter绑定到RecyclerView,不要每次拿到数据都重新调用
setAdapter,反复设置Adapter是导致闪烁的核心原因 - 进入页面时先展示和列表item样式一致的骨架屏占位,避免空白导致的视觉突兀感
- 子线程读取缓存数据完成后,切回主线程调用Adapter的批量数据更新方法(如
notifyDataSetChanged或更高效的局部刷新方法),仅更新Adapter内的数据列表即可
- 页面初始化时,先给RecyclerView设置固定尺寸属性
- 容灾处理:可以在子线程读缓存的同时,轻量校验缓存中50个Uri的有效性,若存在失效的情况再触发一次全量MediaStore扫描,绝大多数场景下都不会走到扫描逻辑,不会产生额外耗时。
内容的提问来源于stack exchange,提问作者Anirudhdhsinh Jadeja
相关产品推荐
相关产品推荐

