當前位置:首頁 » 硬碟大全 » flutterlistview緩存
擴展閱讀
webinf下怎麼引入js 2023-08-31 21:54:13
堡壘機怎麼打開web 2023-08-31 21:54:11

flutterlistview緩存

發布時間: 2023-04-22 18:59:10

⑴ Flutter -Listview 4個優化能讓你的列表絲般順滑

優化點1:使用 builder構建列表
當你的列裂絕表元素是動態增長的時候(比如上拉載入更多),請不要直接用children 的方式,一直往children 的數組增加組件,那樣會很糟糕。對於 ListView.builder 是按需構建列表元素,也就是只有那些可見得元素才會調用itemBuilder 構建元素,這樣對於大列表而言性能開銷自然會小很多。

優化點2:禁用 addAutomaticKeepAlives 和 addRepaintBoundaries 特性
這兩個屬性都是為了優化滾動過程中的用戶體驗的。
addAutomaticKeepAlives 特性默認是 true,意思是在列表元素不可見後可以保持元素的狀態,從而在再次出現在屏幕的時候能夠快速構建。這其實是一個拿空間換時間的方法,會造成一定程度得內存開銷。可以設置為 false 關閉這一特性。缺點是滑動過快的時候可能會出現短暫的白屏(實際會很少發生)。
addRepaintBoundaries 是將列表元素使用一個重繪邊界(Repaint Boundary)包裹,從而使得滾動的時候可以避免重繪。而如果列表很容易繪制(列表元素布局比較簡單的情況下)的時候,可以關閉這個特性來提高滾動的流暢度。

優化點3:盡可能將列表元素中不變的組件使用 const 修飾
使用 const 相當於將元素緩存起來實現共用,若列表元素某些部分一直保持不變,那麼可以使用 const 修飾。

優化點4:使用 itemExtent 確定列表元素滾動方向的尺寸
對於很多列表,我們在滾動方向上的尺寸是提前可以根據 UI設計稿知道的,如果能夠知道的話肆兄姿,那麼使用 itemExtent 屬性制定列表元素在滾動方向的尺寸,可以提升性能。這是因為,如果不指定的話,在滾動過程中,會需要推算每個元素在滾動方向的尺寸從而消耗計算資源。

Flutter ListView 的4個優化要點,非常實用哦!實際上,這些要點都可以從官網的文塵配檔里找出對應得說明。因此,如果遇到了性能問題,除了搜索引擎外,也建議多看看官方的文檔。

⑵ Flutter圖片載入與緩存

其中,參數 image 類型為抽象類 ImageProvider ,定義了圖片數據獲取和載入的相關介面。

根據不同的數據來源,派生出不同的 ImageProvider :

抽象類 ImageProvider 提供了一個用於載入數據源的抽象方法 @protected ImageStreamCompleter load(T key, DecoderCallback decode); 介面,不同的數據源定義各自的實現。

子類 NetworkImage 實現如下:

load 方法返回類型為抽象類 ImageStreamCompleter ,其中定義了一些管理圖片載入過程的介面,比如 addListener 、 removeListener 、 等, 為其子類。

第一個參數 codec 類型為 Future<ui.Codec> ,用來對突破進行解碼,當 codec 准備好的時候桐指雀,就會立即對圖片第一幀進行解碼操作。

codec 為 _loadAsync 方法返回值,

_loadAsync 方法實現:

decode 方法的類型:
其中解碼傳入的回調方法 image_provider.DecoderCallback decode ,

傳入 Uint8List ,返回 Future<ui.Codec> 。

而對 decode 回調方法的具體定義,在 ImageProvider 的 resolveStreamForKey 方法中做了定義, resolveStreamForKey 方法在 ImageProvider 的 resolve 方法中有調用, resolve 方法則為 ImageProvider 類層級結構的公共入口點。

resolveStreamForKey 和 resolve 實現如下:

decode 方法,即 PaintingBinding.instance!.instantiateImageCodec ,即為具體圖片解碼的方法實現。

ui.instantiateImageCodec 實現:

descriptor.instantiateCodec 方法實現:

_instantiateCodec 方法的實現,最終到了 native 的實現:

其中返回值類型 Codec 里定義了一些屬性:

obtainKey 方法:
ImageProvider 定義了一個抽象方法 Future<T> 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提供的方法來設置:

⑶ Flutter 仿企業微信多選-listview可見item位置

有一個需求,是仿企業照微信的多選(效果大家自己去看)。我想到了兩種方案:

思路:我們直接通過listview.builder是沒辦法自定義SliverChildBuilderDelegate,我們可以通過listview.custom來自定義SliverChildBuilderDelegate,通過自定義我們可以重寫didFinishLayout方法,拿到裡面緩存的第一個item和最後一個item。可見item的跟緩存item是差5個的,可以間接算出來,後面發現其實不太行,上下滑動之後會顯示之前滑動時候的可見位置。宏此高 正解是:這個裡面還有個estimateMaxScrollOffset方法,正常來說通過它可以獲取到可見的扒槐第一個和最後一個item位置。但是我一開始使用這個方法,不會被回調,後面不知道修改了什麼,就會回調,然後這個位置是准確的。

看下listview.builder的源碼

我們蔽尺可以看到childrenDelegate是直接定義好了的。

在看看listview.custom 的源碼

childrenDelegate這個是一個必傳參數。

⑷ Flutter 本地緩存

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');`