十年網(wǎng)站開發(fā)經(jīng)驗 + 多家企業(yè)客戶 + 靠譜的建站團(tuán)隊
量身定制 + 運營維護(hù)+專業(yè)推廣+無憂售后,網(wǎng)站問題一站解決
get方法獲取數(shù)據(jù),封裝存儲和移除方法用于操作數(shù)據(jù)緩存列表(需要優(yōu)化,僅參考)

網(wǎng)站設(shè)計制作、成都做網(wǎng)站,成都做網(wǎng)站公司-創(chuàng)新互聯(lián)建站已向數(shù)千家企業(yè)提供了,網(wǎng)站設(shè)計,網(wǎng)站制作,網(wǎng)絡(luò)營銷等服務(wù)!設(shè)計與技術(shù)結(jié)合,多年網(wǎng)站推廣經(jīng)驗,合理的價格為您打造企業(yè)品質(zhì)網(wǎng)站。
其中,參數(shù) image 類型為抽象類 ImageProvider ,定義了圖片數(shù)據(jù)獲取和加載的相關(guān)接口。
根據(jù)不同的數(shù)據(jù)來源,派生出不同的 ImageProvider :
抽象類 ImageProvider 提供了一個用于加載數(shù)據(jù)源的抽象方法 @protected ImageStreamCompleter load(T key, DecoderCallback decode); 接口,不同的數(shù)據(jù)源定義各自的實現(xiàn)。
子類 NetworkImage 實現(xiàn)如下:
load 方法返回類型為抽象類 ImageStreamCompleter ,其中定義了一些管理圖片加載過程的接口,比如 addListener 、 removeListener 、 addOnLastListenerRemovedCallback 等, MultiFrameImageStreamCompleter 為其子類。
MultiFrameImageStreamCompleter 第一個參數(shù) codec 類型為 Futureui.Codec ,用來對突破進(jìn)行解碼,當(dāng) codec 準(zhǔn)備好的時候,就會立即對圖片第一幀進(jìn)行解碼操作。
codec 為 _loadAsync 方法返回值,
_loadAsync 方法實現(xiàn):
decode 方法的類型:
其中解碼傳入的回調(diào)方法 image_provider.DecoderCallback decode ,
傳入 Uint8List ,返回 Futureui.Codec 。
而對 decode 回調(diào)方法的具體定義,在 ImageProvider 的 resolveStreamForKey 方法中做了定義, resolveStreamForKey 方法在 ImageProvider 的 resolve 方法中有調(diào)用, resolve 方法則為 ImageProvider 類層級結(jié)構(gòu)的公共入口點。
resolveStreamForKey 和 resolve 實現(xiàn)如下:
decode 方法,即 PaintingBinding.instance!.instantiateImageCodec ,即為具體圖片解碼的方法實現(xiàn)。
ui.instantiateImageCodec 實現(xiàn):
descriptor.instantiateCodec 方法實現(xiàn):
_instantiateCodec 方法的實現(xiàn),最終到了 native 的實現(xiàn):
其中返回值類型 Codec 里定義了一些屬性:
obtainKey 方法:
ImageProvider 定義了一個抽象方法 FutureT obtainKey(ImageConfiguration configuration); ,供子類來實現(xiàn),其中 NetworkImage 的實現(xiàn)為:
obtainKey 作用:
配合實現(xiàn)圖片緩存, ImageProvider 從數(shù)據(jù)源加載完數(shù)據(jù)后,會在 ImageCache 中緩存圖片數(shù)據(jù),圖片數(shù)據(jù)緩存時一個 Map ,其中 Map 中的 key 便是 obtainKey 。
resolve 作為 ImageProvider 提供給 Image 的主入口方法,參數(shù)為 ImageConfiguration ,
resolve 其中調(diào)用了 _createErrorHandlerAndKey 方法,設(shè)置了成功回調(diào)和失敗回調(diào):
其中 _createErrorHandlerAndKey 方法的實現(xiàn),便調(diào)用了 obtainKey 來設(shè)置 key 。
在成功回調(diào)里,調(diào)用了方法 resolveStreamForKey ,里面有具體的緩存實現(xiàn) PaintingBinding.instance!.imageCache!.putIfAbsent :
PaintingBinding.instance!.imageCache 是ImageCache的一個實例,是 PaintingBinding 的一個屬性,是一個單例,圖片緩存是全局的。
如上述判斷:
ImageCache 定義:
ImageCache 緩存池:
在 NetworkImage 中,對 ImageProvider 的抽象方法 obtainKey 進(jìn)行了實現(xiàn),將自己創(chuàng)建了一個同步 Future 進(jìn)行返回:
同時,自身又重寫了 ImageProvider 定義的 == 比較操作符,通過圖片 url 和圖片的縮放比例 scale 進(jìn)行比較:
通過ImageCache提供的方法來設(shè)置:
Flutter的圖片緩存機制有問題(可能是我使用的版本1.12.13有問題)
網(wǎng)絡(luò)圖片會默認(rèn)緩存到本地,但是不管圖片是不是完整的或者損壞的,導(dǎo)致頁面在下次進(jìn)入的時候會優(yōu)先從緩存里讀取圖片。有些圖片是沒有加載完成的,或者損壞的,導(dǎo)致圖片無法顯示。UI效果就是顯示成白色的。
一種解決方式:加載前或者退出后清理圖片緩存
ImageCache??imageCache?=?PaintingBinding.instance.imageCache;?
imageCache.clear();
缺點就是每次圖片都想要從網(wǎng)絡(luò)上獲取,增加服務(wù)器負(fù)擔(dān)
Flutter本地存儲可以用 shared_preferences ,其會根據(jù)不同操作系統(tǒng)進(jìn)行相對應(yīng)的存儲。
在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;
}
}
```
在項目初始頁調(diào)用
`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');`
FadeInImage官方默認(rèn)只支持緩存到內(nèi)存中,在項目中一般都需要把圖片緩存到本地文件中
通過觀察 FadeInImage 的構(gòu)造函數(shù)中,得知 image 是調(diào)用 ResizeImage.resizeIfNeeded(imageCacheWidth, imageCacheHeight, NetworkImage(image, scale: imageScale)) 這個方法來獲得圖片的,而獲得 ImageProvider 又是通過 NetworkImage(image, scale: imageScale)
繼續(xù)跟進(jìn)發(fā)現(xiàn) NetworkImage 是繼承 ImageProvider 的一個抽象類,里面有個工廠構(gòu)造函數(shù)
通過修改這里的源碼來實現(xiàn)本地緩存圖片
在這之前需要先導(dǎo)入
在默認(rèn)情況下頁面切換走時會被銷毀,頁面切換回來時會被重新創(chuàng)建,如果頁面中有列表那么整個列表將會被重新創(chuàng)建,降低了用戶體驗,下面是解決這個問題的幾種處理方式