Flutter无OOM实现媲美iOS原生速度加载手机相册方案咨询
Flutter相册加载性能优化方案
方案1:开箱即用的高流畅实现(可匹配原生iOS体验)
直接采用成熟生态的最佳实践,不需要自行维护缓存逻辑:
- 缩略图加载固定匹配item尺寸请求:使用
photo_manager的AssetEntity.thumbnailDataWithSize接口,根据你的GridViewitem实际尺寸传入thumbSize参数,比如item为120*120就传const [120, 120],禁止请求原图再做缩放,大幅降低IO和内存开销 - 用
extended_image组件做缩略图渲染,自带LRU内存缓存策略,可通过ExtendedImage.defaultMaxMemoryCacheCount配置最大缓存数,默认的缓存淘汰逻辑已经可以避免OOM,同时支持占位图、错误图配置,不会出现白屏闪烁 - 优化
GridView.builder配置:设置addAutomaticKeepAlives: false、addRepaintBoundaries: true、cacheExtent: 300,减少无效widget重绘,提前预加载视口外相邻区域的内容 - 若不需要高度自定义布局,可直接使用
wechat_assets_picker库,该库已经做了全链路性能优化,默认滚动流畅度和iOS原生相册一致,支持自定义UI样式适配业务需求
方案2:现有内存缓存算法优化(针对你当前的Map缓存方案)
核心思路是绑定视口范围做动态缓存,搭配LRU淘汰策略避免OOM:
- 替换你当前使用的普通
Map为LRU缓存实现,可直接使用lru_cache第三方库,设置最大缓存数量为60(按你要求的视口上下各15个计算,常规视口内约15个资源,总缓存45个,留15个冗余即可),超过阈值自动淘汰最久未使用的缓存资源,从根源避免内存溢出 - 给
GridView绑定ScrollController,监听滚动事件:每次滚动结束后,通过controller.position计算当前视口内可见的第一个item索引startIdx和最后一个item索引endIdx - 每次计算完视口索引后,将预加载缓存范围设置为
[max(0, startIdx - 15), min(资源总数 - 1, endIdx + 15)],仅保留该范围内的缩略图数据在内存中,超出范围的缓存主动调用clear释放 - 增加加载优先级调度:当前视口内的资源加载优先级最高,视口外的预加载资源优先级调低,避免滚动时IO资源抢占导致UI卡顿
- 所有缩略图解码逻辑放到Isolate中执行,不要阻塞主UI线程,解码完成后再抛回主线程渲染,进一步降低滚动掉帧概率
内容的提问来源于stack exchange,提问作者Tom3652
相关产品推荐
相关产品推荐

