Flutter 长图列表不卡顿的三个取舍:缓存、预加载与内存上限

举报
某不科学的高数 发表于 2026/11/03 10:38:56 2026/11/03
【摘要】 做图片多的长列表时,流畅度很少是某一个优化带来的,更多是缓存、预加载和内存上限三者之间的取舍。本文结合实战经验,讲清楚每一层该怎么定、以及常见的踩坑点。

做图片浏览类应用时,最容易被低估的一点是:列表滑起来卡,往往不是某一帧写得慢,而是内存、解码和网络请求在同一时间撞在了一起。用户快速滑动时,屏幕上要显示新图、后台要下载下一批图、旧图还要占着内存,任何一环没有上限,都会变成卡顿甚至闪退。

我后来处理这类问题的方法,是先把目标定下来:滑动时不掉帧、内存有明确上限、弱网下也不至于一片空白。在这个目标下,缓存、预加载和内存上限要一起设计,而不是各做各的。

一、缓存要分层,不要只留一层

很多人只用内存缓存,觉得够快就行。但内存缓存的问题是容量有限,一旦被系统回收,重新解码和重新下载的代价都很大。更稳的做法是分三层:内存缓存管当前可见区域和临近区域,磁盘缓存管最近看过的内容,网络只作为最后的兜底。

分层的关键是每一层都有自己的淘汰规则。内存层按张数和字节数双重限制,磁盘层按总大小和保存时间限制,超过就按最近最少使用淘汰。没有淘汰规则的缓存,本质上就是内存泄漏的另一种写法。还要注意,缓存的键要稳定,不能把临时地址、带签名的链接直接当作键,否则同一张图会被反复存成多份。

二、预加载不是越多越好

预加载很容易走向两个极端:不预加载,翻页就等图;预加载太多,后台请求把当前页的带宽和解码资源都抢走了。我的经验是,预加载只做“下一步最可能用到的”,而不是“后面所有可能用到的”。

具体来说,正在看第 N 页时,预加载 N+1 页就够了,最多再带上 N+2 页的低优先级请求。滑动方向变了,旧的预加载任务要能取消,而不是继续占着队列。还要区分网络环境:在 Wi-Fi 下可以适当放宽,在移动网络下要收紧,甚至只预加载缩略图,等用户真正翻到那一页再拉原图。

三、给内存设一个硬上限

Flutter 自带的图片缓存默认并不小,如果不主动设上限,长列表很容易在低端机上先把内存吃满。可以主动设置图片缓存的张数和字节上限,例如:

final imageCache = PaintingBinding.instance.imageCache;
imageCache.maximumSize = 100;
imageCache.maximumSizeBytes = 100 << 20;

数字本身没有标准答案,要按机型和图片尺寸调。更重要的是,上限要和业务行为联动:离开阅读页时清理不在视野内的图片,收到系统内存警告时先降级而不是硬扛。很多闪退不是因为某一刻内存特别高,而是因为峰值没有被管住。

四、解码尺寸要和显示尺寸匹配

另一个常见浪费,是用原图尺寸去解码,再缩放到屏幕上显示。一张几千像素的图片,解码后的内存占用远比文件大小大得多。如果显示区域只有几百像素,就应该按显示尺寸请求或解码对应规格的图片。

在列表里还要避免重复解码。滚动时同一张图如果反复进出视野,缓存命中率比解码速度更重要。先保证缓存键、尺寸规格一致,再去谈解码线程和并发数,否则优化很容易做在错误的地方。

五、失败时要有降级,而不是空白

网络请求一定会失败,缓存也一定会有 miss。好的体验不是“永远不失败”,而是失败时有明确的降级路径:先显示占位图或低清图,失败后允许用户点一下重试,连续失败时不要无限重试。

降级也要分层:单张图失败只影响那一张,不要让整个列表停住;整批请求失败时,给出可重试的入口,而不是静默地停在空白页。这些细节写起来不难,却是用户感知最明显的地方。

结尾:先定上限,再谈优化

总结一下我的检查清单:内存和磁盘缓存有没有淘汰规则;预加载是不是只覆盖下一步、且能取消;图片缓存有没有硬上限;解码尺寸是不是按显示尺寸来;失败时有没有单张重试和低清降级。

把这五条先做到,多数长图列表的卡顿都会明显缓解。剩下的,才是值得花时间去 profiling 的个别瓶颈,而不是一上来就到处加缓存、加并发。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。