網站首頁 編程語言 正文
引言
設計: 嗯? 這個圖片點擊跳轉進詳情再返回圖片怎么變白閃一下呢?
產品: 是啊是啊! 一定是個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
相關推薦
- 2022-07-14 利用Matlab實現圖像亮度分布統計圖_C 語言
- 2021-12-02 C語言GetStdHandle函數使用方法_C 語言
- 2023-01-28 一文詳解Go語言fmt標準庫的常用占位符使用_Golang
- 2022-07-07 Android?配合Mat工具監聽查找內存泄漏的操作方法_Android
- 2022-07-07 通過Golang編寫一個AES加密解密工具_Golang
- 2022-08-22 C++動態規劃計算最大子數組_C 語言
- 2023-03-02 golang中new與make的區別講解_Golang
- 2022-06-08 記錄linux ens33網卡啟動失敗的問題
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支