十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
get方法获取数据,封装存储和移除方法用于操作数据缓存列表(需要优化,仅参考)
成都创新互联是一家成都网站建设、网站制作,提供网页设计,网站设计,网站制作,建网站,按需设计,网站开发公司,从2013年成立是互联行业建设者,服务者。以提升客户品牌价值为核心业务,全程参与项目的网站策划设计制作,前端开发,后台程序制作以及后期项目运营并提出专业建议和思路。
Flutter本地存储可以用 shared_preferences ,其会根据不同操作系统进行相对应的存储。
在pubspec.yaml添加
`shared_preferences: ^2.0.13`
```d
import 'package:shared_preferences/shared_preferences.dart';
class SpUtils {
SharedPreferences?prefs;
SpUtils._() {
init();
}
static SpUtils?_instance;
static preInit() {
_instance ??=SpUtils._();
}
static SpUtilsgetInstance() {
_instance ??=SpUtils._();
return _instance!;
}
void init()async {
prefs ??=await SharedPreferences.getInstance();
}
setString(String key, String value) {
prefs!.setString(key, value);
}
setDouble(String key, double value) {
prefs!.setDouble(key, value);
}
setInt(String key, int value) {
prefs!.setInt(key, value);
}
setBool(String key, bool value) {
prefs!.setBool(key, value);
}
setStringList(String key, List value) {
prefs!.setStringList(key, value);
}
clear(String key){
prefs!.remove(key);
}
clearAll(){
prefs!.clear();
}
Tget(String key) {
return prefs!.get(key)as T;
}
}
```
在项目初始页调用
`SpUtils.preInit();`
存
`SpUtils.getInstance().setString('userId', '12345678');`
`SpUtils.getInstance().setDouble('price', 12.88);`
`SpUtils.getInstance().setInt('count', 200);`
`SpUtils.getInstance().setBool('flag', true);`
取
`SpUtils.getInstance().get('userId');`
删
`SpUtils.getInstance().clearAll();`
`SpUtils.getInstance().clear('userId');`
Flutter的图片缓存机制有问题(可能是我使用的版本1.12.13有问题)
网络图片会默认缓存到本地,但是不管图片是不是完整的或者损坏的,导致页面在下次进入的时候会优先从缓存里读取图片。有些图片是没有加载完成的,或者损坏的,导致图片无法显示。UI效果就是显示成白色的。
一种解决方式:加载前或者退出后清理图片缓存
ImageCache imageCache = PaintingBinding.instance.imageCache;
imageCache.clear();
缺点就是每次图片都想要从网络上获取,增加服务器负担
在默认情况下页面切换走时会被销毁,页面切换回来时会被重新创建,如果页面中有列表那么整个列表将会被重新创建,降低了用户体验,下面是解决这个问题的几种处理方式
其中,参数 image 类型为抽象类 ImageProvider ,定义了图片数据获取和加载的相关接口。
根据不同的数据来源,派生出不同的 ImageProvider :
抽象类 ImageProvider 提供了一个用于加载数据源的抽象方法 @protected ImageStreamCompleter load(T key, DecoderCallback decode); 接口,不同的数据源定义各自的实现。
子类 NetworkImage 实现如下:
load 方法返回类型为抽象类 ImageStreamCompleter ,其中定义了一些管理图片加载过程的接口,比如 addListener 、 removeListener 、 addOnLastListenerRemovedCallback 等, MultiFrameImageStreamCompleter 为其子类。
MultiFrameImageStreamCompleter 第一个参数 codec 类型为 Futureui.Codec ,用来对突破进行解码,当 codec 准备好的时候,就会立即对图片第一帧进行解码操作。
codec 为 _loadAsync 方法返回值,
_loadAsync 方法实现:
decode 方法的类型:
其中解码传入的回调方法 image_provider.DecoderCallback decode ,
传入 Uint8List ,返回 Futureui.Codec 。
而对 decode 回调方法的具体定义,在 ImageProvider 的 resolveStreamForKey 方法中做了定义, resolveStreamForKey 方法在 ImageProvider 的 resolve 方法中有调用, resolve 方法则为 ImageProvider 类层级结构的公共入口点。
resolveStreamForKey 和 resolve 实现如下:
decode 方法,即 PaintingBinding.instance!.instantiateImageCodec ,即为具体图片解码的方法实现。
ui.instantiateImageCodec 实现:
descriptor.instantiateCodec 方法实现:
_instantiateCodec 方法的实现,最终到了 native 的实现:
其中返回值类型 Codec 里定义了一些属性:
obtainKey 方法:
ImageProvider 定义了一个抽象方法 FutureT obtainKey(ImageConfiguration configuration); ,供子类来实现,其中 NetworkImage 的实现为:
obtainKey 作用:
配合实现图片缓存, ImageProvider 从数据源加载完数据后,会在 ImageCache 中缓存图片数据,图片数据缓存时一个 Map ,其中 Map 中的 key 便是 obtainKey 。
resolve 作为 ImageProvider 提供给 Image 的主入口方法,参数为 ImageConfiguration ,
resolve 其中调用了 _createErrorHandlerAndKey 方法,设置了成功回调和失败回调:
其中 _createErrorHandlerAndKey 方法的实现,便调用了 obtainKey 来设置 key 。
在成功回调里,调用了方法 resolveStreamForKey ,里面有具体的缓存实现 PaintingBinding.instance!.imageCache!.putIfAbsent :
PaintingBinding.instance!.imageCache 是ImageCache的一个实例,是 PaintingBinding 的一个属性,是一个单例,图片缓存是全局的。
如上述判断:
ImageCache 定义:
ImageCache 缓存池:
在 NetworkImage 中,对 ImageProvider 的抽象方法 obtainKey 进行了实现,将自己创建了一个同步 Future 进行返回:
同时,自身又重写了 ImageProvider 定义的 == 比较操作符,通过图片 url 和图片的缩放比例 scale 进行比较:
通过ImageCache提供的方法来设置: