Flutter Image 缓存剖析

背景
图片展示是应用程序中最常见的功能,在android中有一些很经典的库来处理图片的缓存,广泛应用例如ImageLoader,Glide,Frescho,flutter官方提供了Image的widget来展示图片,Image内部封装了具体文件数据如何获取,以及数据怎么缓存;
image widget分析
Image 是一个StateFullWidget,除了默认构造函数外,还提供了命名构造函数,覆盖了常见的文件获取途径:
Image.network
Image.file
Image.asset
Image.memory

_ImageState的didChangeDependencies函数会对图片进行解析,
在这里插入图片描述
_resolveImage函数主要有两个步骤:
在这里插入图片描述

1、解析图片,返回ImageStream对象;
2、对ImageStream添加监听器,当图片解析完成后,通过setState刷新Widget;
所以关键步骤在步骤1,实际上是调用成员变量image的resolve方法,这里的image实际上是ImageProvier:
在这里插入图片描述
ImageProvier是一个抽象类,image是在构造函数里初始化的,例如Image.file:
在这里插入图片描述

本文就以FileImage作为目标分析一个本地文件图片的解析过程:
FileImage类并没有复写resolve方法,实现是在父类ImageProvier中,该法完成了两个步骤:
1、生成ImageStreamCompleter对象:
在这里插入图片描述
2、将completer设置到ImageStream中去,返回这个ImageStream;

所以关键步骤是1,这里是调了PaintingBinding.instance
.imageCache的putIfAbsent方法,正是在这个方法里面体现了image缓存策略,分为四个步骤
1、从_pendingImages获取图片:
在这里插入图片描述
如果result不空,说明这个图片还在解析中,直接返回这个解析中的 result;
2、从_cache查找是否存在,如果存在则返回缓存对象:
在这里插入图片描述
3、执行真正的解析:
在这里插入图片描述
loader是ImageProvider里的抽象函数,具体实现在各个子类中,例如在FileImage中:
在这里插入图片描述
返回的是一个MultiFrameImageStreamCompleter的对象,说明是支持Gif的。
4、构造一个_PendingImage对象,存入_pendingImages,就是步骤1获取的数据,直到图片解析完成后首先执行_pendingImages的监听器,在监听器内部实现图片数据进缓存,和check缓存池size;
在这里插入图片描述
下面看MultiFrameImageStreamCompleter,在构造函数内部执行真正的Load操作:
在这里插入图片描述
Future执行完后的回调_handleCodecReady 最终进入_decodeNextFrameAndSchedule,
在这里插入图片描述
对于单帧图片的文件解析完就返回给了Image的监听器,对于多帧图片,除了通知Image的监听器外,还会继续解析下一帧;
这个样整个FileImage的解析过程就走完了。

总结:
1、ImageCache是一个比较简单的Lru的缓存,缓存的数据都在内存级别,没有做持久化的数据缓存;
2、ImageCache提供了Evict函数,用于清理缓存,这是优化内存的一种切入点;
对于gif图的解析需要注意的是:
1、如果只需要展示首帧图片的话,需要再解析完成后,清理removeListener.
2、退出界面后要调用evict方法,来清理缓存,否则下次进来会看到的是下一帧的图片。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Flutter中清除缓存可以通过以下步骤实现[^1]: 1. 导入`path_provider`包: ```dart import 'package:path_provider/path_provider.dart'; ``` 2. 获取缓存目录: ```dart Directory cacheDir = await getTemporaryDirectory(); ``` 3. 计算缓存大小: ```dart int cacheSize = 0; List<FileSystemEntity> files = cacheDir.listSync(recursive: true); for (FileSystemEntity file in files) { if (file is File) { cacheSize += await file.length(); } } ``` 4. 删除缓存文件: ```dart for (FileSystemEntity file in files) { if (file is File) { await file.delete(recursive: true); } } ``` 下面是一个完整的示例代码: ```dart import 'dart:io'; import 'package:flutter/material.dart'; import 'package:path_provider/path_provider.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Cache Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: MyHomePage(), ); } } class MyHomePage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Flutter Cache Demo'), ), body: Center( child: RaisedButton( child: Text('Clear Cache'), onPressed: () async { Directory cacheDir = await getTemporaryDirectory(); int cacheSize = 0; List<FileSystemEntity> files = cacheDir.listSync(recursive: true); for (FileSystemEntity file in files) { if (file is File) { cacheSize += await file.length(); } } for (FileSystemEntity file in files) { if (file is File) { await file.delete(recursive: true); } } showDialog( context: context, builder: (BuildContext context) { return AlertDialog( title: Text('Cache Cleared'), content: Text('Cache size: ${cacheSize ~/ 1024} KB'), actions: <Widget>[ FlatButton( child: Text('OK'), onPressed: () { Navigator.of(context).pop(); }, ), ], ); }, ); }, ), ), ); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值