Flutter图片缓存管理ImageCache原理分析
作者:WeninerIo 发布时间:2023-08-20 23:26:19
引言
设计: 嗯? 这个图片点击跳转进详情再返回图片怎么变白闪一下呢?
产品: 是啊是啊! 一定是个bug
开发: 囧囧囧
在开发过程中, 也许你也遇到过这样一个场景. 进入一个页面后,前一个页面的图片都会闪白一下. 或者在列表中,加载很多列表项后,之前列表中的图片都需要重新加载.你有没有想过这一切的原因是什么呢?
没错! 它就是我们今天介绍的主人公 --- ImageCache
可能有些人对ImageCache还有些陌生, 我们在之前的章节有说过启动流程时Flutter runApp到渲染上屏,有介绍过其中PaintingBinding这个mixin类.带着探索的心我们先去看看PaintingBinding都做了 一些什么操作呢?
PaintingBinding
PaintingBinding在构造函数中,除了构建自身的实例.同时也构建了图片缓存的管理实例.也包括了着色器预热.
{
_instance = this;
// 创建了图片缓存管理
_imageCache = createImageCache();
shaderWarmUp?.execute();
}
着色器预热可能大部分人都没有接触过,我们只需要知道通过着色器预热,可以提高首次编译的速度即可.有兴趣可以看一下这篇文章着色器预热; 我们现在把目光重新聚焦到今天的主题, 也就是createImageCache()这里.可以看到它直接返回了一个ImageCache的对象. 这里我们暂且不谈ImageCache, 再去看看在PaintingBinding有没有和ImageCache相关的一些代码吧.
@override
void evict(String asset) {
// 调用了rootBundle.evict(asset);
// 也就是从缓存中移除这个key的资源
super.evict(asset);
// 清除所有已显示和不再用到的图片缓存
imageCache.clear();
// 清除所有实时引用的图片缓存
imageCache.clearLiveImages();
}
@override
void handleMemoryPressure() {
// rootBundle.clear();
// 当操作系统通知应用程序内存压力情况时调用。
// 清除所有的图片资源
super.handleMemoryPressure();
imageCache.clear();
}
可以看到, 基本上所有的引用都避不开内存问题. 也就是文章开头出现的bug. 那么,为什么会出现闪白呢? 有多种可能,有可能是系统感受到了内存压力调用了handleMemoryPressure() 方法,清除了图片缓存,或者在ImageCache中,达到了最大缓存,因此内部根据least-recently-used的原则回收了图片缓存.所以回头再看的时候,图片又重新加载了一遍.自然发生了闪白现象. 既然知道了原因,那么解决问题的方法:
减少图片缓存
增大图片缓存的阀值,让系统感觉到压力的阀值提升 我们来分别分析一下两者的可行性
减少图片缓存
如果要减少图片缓存, 我们要知道图片的内存是怎么计算的? 图片内存=分辨率*每个像素点大小 减少的方法也就出来了:
减少分辨率
也就是降低采样率.flutter中即cacheHeight和cacheWidth减少像素点大小
这里也就是像素点的格式,ALPHA_8、RGB_565、ARGB_4444、ARGB_8888、RGBA_F16这些
增大阀值
这里需要去看一下ImageCache中.我们推断一下,什么情况下一个缓存池会达到阀值呢? 那一定是有新图片插入,所以总量才会提升才会够到阀值的门槛.我们找一下有没有相关的方法. 嗯哼~ 果然有一个_checkCacheSize
{
...
// 只要当前的内存超标就会一直执行下去
while (_currentSizeBytes > _maximumSizeBytes || _cache.length > _maximumSize) {
// 根据least-recently-used这个逻辑去依次清除图片缓存
final Object key = _cache.keys.first;
final _CachedImage image = _cache[key]!;
_currentSizeBytes -= image.sizeBytes!;
image.dispose();
_cache.remove(key);
}
...
}
说明我们阀值取决于_maximumSizeBytes和_maximumSize, 一个负责最大缓存图片内存,一个负责最大缓存图片数. 也就是说我们更新这两个指就可以改变图片内存的阀值.从而减少内存回收的频率.
思考
很多问题的发生实际上源码中都有些提示, 带着问题去看收获的远远比单独阅读源码要有收获的多.
这里是weniner,一个在奋斗的flutter. 有些收获的话,不妨点个关注哦!
来源:https://juejin.cn/post/7169049030800965663
猜你喜欢
- 前言之前我们提到了 CustomPaint er 的 Paint 可以使用渐变(GradientShader)来填充绘制的图形,本篇我们来介
- 简介AccessibilityService的设计初衷是为了辅助有身体缺陷的群体使用Android应用,它的设计贯穿着Android的控件树
- 反射方式获取JPA Entity属性和值在记录日志或者调试的时候,往往需要输出数据库查询或者写入的值,或者在接 * 互的时候,可能需要将实体转
- 概述:Flutter中常用的滑动布局 ScrollView 有 SingleChildScrollView、NestedScrollView
- 对Jpa Entity关系映射中mappedBy的理解mappedBy 单向关系不需要设置该属性,双向关系必须设置,避免双方都建立外键字段数
- 接触过Android开发的同学们都知道在Android中访问程序资源基本都是通过资源ID来访问。这样开发起来很简单,并且可以不去考虑各种分辨
- 前言之前用简书的时候一直是在web端,后来下载了客户端,看到了搜索的那个动画,就尝试的去写了,没写之前感觉挺容易的,写了之后,就感觉里面还是
- [LeetCode] 131.Palindrome Partitioning 拆分回文串Given a string s, par
- 一、问题Flutter原有的图片缓存机制,是通过PaintingBinding.instance!.imageCache来管理缓存的,这个缓
- 本文介绍Android中的5种数据存储方式。数据存储在开发中是使用最频繁的,在这里主要介绍Android平台中实现数据存储的5种方式,分别是
- 格式要求:SU MO TU WE TH FR SA &nb
- 这是Hadoop学习全程记录第1篇,在这篇里我将介绍一下如何在Linux下安装Hadoop1.x。先说明一下我的开发环境:虚拟机:VMwar
- 一、Monkey 是什么?Monkey 就是SDK中附带的一个工具。二、Monkey 测试的目的?:该工具用于进行压力测试。 然后开发人员结
- Java泛型映射不同的值类型详解前言:一般来说,开发人员偶尔会遇到这样的情形: 在一个特定容器中映射任意类型的值。然而Java 集合API只
- 就网络和应用程序而言,键盘快捷键很重要,今天我们要谈的便是让这类快捷键得以在Flutter运作的小部件:Focus、Shortcuts和Ac
- 最近几年玩得最疯狂的应该是发红包了,尤其是过年的时候特别受欢迎,下面写了红包的随机算法,其实挺简单的,仅是提供一种思路,希望可以给大家一些启
- strcpy函数详解如下1.函数介绍1.1.函数接口char * __cdecl strcpy(char * dst, const char
- 错误处理到目前为止,我们都没怎么介绍onComplete()和onError()函数。这两个函数用来通知订阅者,被观察的对象将停止发送数据以
- 前言最近看插件库上少有的取色器大都是圆形的或者奇奇怪的的亚子,所以今天做两个矩形的颜色取色器提示:以下是本篇文章正文内容,下面案例可供参考一
- 【程序1】题目:有1、2、3、4个数字,能组成多少个互不相同且无重复数字的三位数?都是多少?1.程序分析:可填在百位、十位、个位的数字都是1