打開(kāi) pubspec.yaml 文件,找到 assets: 開(kāi)頭的Key,將其注釋放開(kāi)并配置正確路徑
目前創(chuàng)新互聯(lián)建站已為1000多家的企業(yè)提供了網(wǎng)站建設(shè)、域名、網(wǎng)絡(luò)空間、網(wǎng)站托管、企業(yè)網(wǎng)站設(shè)計(jì)、寧海網(wǎng)站維護(hù)等服務(wù),公司將堅(jiān)持客戶(hù)導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶(hù)和合作伙伴齊心協(xié)力一起成長(zhǎng),共同發(fā)展。
一. flutter中我們想加載本地圖片,需要兩步:
二. flutter項(xiàng)目中本地圖片加載的原理
在加載圖片時(shí),系統(tǒng)自動(dòng)會(huì)根據(jù)屏幕分辨率優(yōu)先選擇到符合自己分配率的文件夾(2.0x或者3.0x或者4.0x)下去取相對(duì)應(yīng)的圖片,如果當(dāng)前文件夾下沒(méi)有,則會(huì)到低一倍的文件夾下去,如果還沒(méi)有,則繼續(xù)向更低一倍去取。(比如:iOS 5.5英寸及以上屏幕會(huì)優(yōu)先選擇去3.0x下去取圖片,如果3.0x不存在或者3.0x文件夾下沒(méi)有,則去2.0x下??;如果2.0x不存在或者2.0x下沒(méi)有,則去1.0x下??;1.0x下再?zèng)]有,則在images文件下取)。
其中,參數(shù) image 類(lèi)型為抽象類(lèi) ImageProvider ,定義了圖片數(shù)據(jù)獲取和加載的相關(guān)接口。
根據(jù)不同的數(shù)據(jù)來(lái)源,派生出不同的 ImageProvider :
抽象類(lèi) ImageProvider 提供了一個(gè)用于加載數(shù)據(jù)源的抽象方法 @protected ImageStreamCompleter load(T key, DecoderCallback decode); 接口,不同的數(shù)據(jù)源定義各自的實(shí)現(xiàn)。
子類(lèi) NetworkImage 實(shí)現(xiàn)如下:
load 方法返回類(lèi)型為抽象類(lèi) ImageStreamCompleter ,其中定義了一些管理圖片加載過(guò)程的接口,比如 addListener 、 removeListener 、 addOnLastListenerRemovedCallback 等, MultiFrameImageStreamCompleter 為其子類(lèi)。
MultiFrameImageStreamCompleter 第一個(gè)參數(shù) codec 類(lèi)型為 Futureui.Codec ,用來(lái)對(duì)突破進(jìn)行解碼,當(dāng) codec 準(zhǔn)備好的時(shí)候,就會(huì)立即對(duì)圖片第一幀進(jìn)行解碼操作。
codec 為 _loadAsync 方法返回值,
_loadAsync 方法實(shí)現(xiàn):
decode 方法的類(lèi)型:
其中解碼傳入的回調(diào)方法 image_provider.DecoderCallback decode ,
傳入 Uint8List ,返回 Futureui.Codec 。
而對(duì) decode 回調(diào)方法的具體定義,在 ImageProvider 的 resolveStreamForKey 方法中做了定義, resolveStreamForKey 方法在 ImageProvider 的 resolve 方法中有調(diào)用, resolve 方法則為 ImageProvider 類(lèi)層級(jí)結(jié)構(gòu)的公共入口點(diǎn)。
resolveStreamForKey 和 resolve 實(shí)現(xiàn)如下:
decode 方法,即 PaintingBinding.instance!.instantiateImageCodec ,即為具體圖片解碼的方法實(shí)現(xiàn)。
ui.instantiateImageCodec 實(shí)現(xiàn):
descriptor.instantiateCodec 方法實(shí)現(xiàn):
_instantiateCodec 方法的實(shí)現(xiàn),最終到了 native 的實(shí)現(xiàn):
其中返回值類(lèi)型 Codec 里定義了一些屬性:
obtainKey 方法:
ImageProvider 定義了一個(gè)抽象方法 FutureT obtainKey(ImageConfiguration configuration); ,供子類(lèi)來(lái)實(shí)現(xiàn),其中 NetworkImage 的實(shí)現(xiàn)為:
obtainKey 作用:
配合實(shí)現(xiàn)圖片緩存, ImageProvider 從數(shù)據(jù)源加載完數(shù)據(jù)后,會(huì)在 ImageCache 中緩存圖片數(shù)據(jù),圖片數(shù)據(jù)緩存時(shí)一個(gè) Map ,其中 Map 中的 key 便是 obtainKey 。
resolve 作為 ImageProvider 提供給 Image 的主入口方法,參數(shù)為 ImageConfiguration ,
resolve 其中調(diào)用了 _createErrorHandlerAndKey 方法,設(shè)置了成功回調(diào)和失敗回調(diào):
其中 _createErrorHandlerAndKey 方法的實(shí)現(xiàn),便調(diào)用了 obtainKey 來(lái)設(shè)置 key 。
在成功回調(diào)里,調(diào)用了方法 resolveStreamForKey ,里面有具體的緩存實(shí)現(xiàn) PaintingBinding.instance!.imageCache!.putIfAbsent :
PaintingBinding.instance!.imageCache 是ImageCache的一個(gè)實(shí)例,是 PaintingBinding 的一個(gè)屬性,是一個(gè)單例,圖片緩存是全局的。
如上述判斷:
ImageCache 定義:
ImageCache 緩存池:
在 NetworkImage 中,對(duì) ImageProvider 的抽象方法 obtainKey 進(jìn)行了實(shí)現(xiàn),將自己創(chuàng)建了一個(gè)同步 Future 進(jìn)行返回:
同時(shí),自身又重寫(xiě)了 ImageProvider 定義的 == 比較操作符,通過(guò)圖片 url 和圖片的縮放比例 scale 進(jìn)行比較:
通過(guò)ImageCache提供的方法來(lái)設(shè)置:
Flutter的圖片緩存機(jī)制有問(wèn)題(可能是我使用的版本1.12.13有問(wèn)題)
網(wǎng)絡(luò)圖片會(huì)默認(rèn)緩存到本地,但是不管圖片是不是完整的或者損壞的,導(dǎo)致頁(yè)面在下次進(jìn)入的時(shí)候會(huì)優(yōu)先從緩存里讀取圖片。有些圖片是沒(méi)有加載完成的,或者損壞的,導(dǎo)致圖片無(wú)法顯示。UI效果就是顯示成白色的。
一種解決方式:加載前或者退出后清理圖片緩存
ImageCache??imageCache?=?PaintingBinding.instance.imageCache;?
imageCache.clear();
缺點(diǎn)就是每次圖片都想要從網(wǎng)絡(luò)上獲取,增加服務(wù)器負(fù)擔(dān)