天天看點

Flutter FutureBuilder 異步 UI 神器

一般程式員都會了解,類似于 IO、網絡請求等都應該是 異步 的。在Dart中,我們使用 Future 來管理,這樣就不用擔心線程或者死鎖的問題。

那麼當 Flutter 涉及到 Future 的時候,widget 該如何去建構呢?在網絡請求 開始前、請求中、請求完成或失敗,我們應該如何去管理我們的UI?

為此,Flutter 推出 FutureBuilder。

先看文檔:

翻譯過來說就是 FutureBuilder 是基于 Future 快照來建構自身的一個元件。

快照是啥玩意?個人了解就是這個 Future 目前的資訊。

這個資訊裡面包括: 目前的狀态、所攜帶的資料等等 。

先看看 FutureBuilder 是個啥, 點開源碼:

看出來是個有狀态的小部件,找到 State 的 build 方法:

build 方法直接傳回了一個 widget 的 builder。

那我們繼續,打開官網看官方Demo怎麼寫的:

可以看到 FutureBuilder 定義了一個泛型,這個泛型是用來擷取快照中資料時用的。

FlutureBuilder 有兩個參數:

future:這個參數需要一個 Future 對象,類似于 網絡請求、IObuilder:這個參數需傳回一個 widget,我們可以看到 demo 中根據現在快照不同的連接配接狀态傳回不同的 widget。

我們再來看一下 snapshot.connectionState 都有哪些值:

<col>

ConnectionState

目前沒有連接配接到任何的異步任務

ConnectionState.none

ConnectionState.waiting

連接配接到異步任務并等待進行互動

ConnectionState.active

連接配接到異步任務并開始互動

ConnectionState.done

異步任務中止

現在了解了之後我們就可以有想法了。我們在打開一個頁面的時候肯定會有網絡請求,這個時候要顯示 loading 之類的,我們就可以利用目前快照的狀态來傳回不同的 widget

首先看build代碼:

Scaffold 的 body 直接傳回一個 FutureBuilder,根據不同狀态來傳回了不同的 widget。

這裡需要注意的一點是:我們知道 StatefulWidget會長時間維護一個 State,當有變動的時候會調用 didUpdateWidget 方法,就要重新build了。是以 FutureBuilder 的官方文檔上有這麼一段文字:

The future must have been obtained earlier, e.g. during State.initState, State.didUpdateConfig , or State.didChangeDependencies. It must not be created during the State.build or StatelessWidget.buildmethod call when constructing the FutureBuilder. If the future is created at the same time as the FutureBuilder, then every time the FutureBuilder's parent is rebuilt, the asynchronous task will be restarted.A general guideline is to assume that every build method could get called every frame, and to treat omitted calls as an optimization.

大緻意思就是說 future 這個參數建議在 initState() 裡初始化,不要在 build 方法裡初始化,這樣的話會一直 rebuild。

為什麼呢,我們檢視 didUpdateWidget 源碼:

可以看出來這裡是判斷了 future 這個字段, 是以我們一定不要在 build 方法裡初始化 future 參數!

是以,我們在 initState()方法裡初始化:

generateListView 方法就不放了,就是基本的 ListView.builder()。

這樣我們就完成了上圖的效果,在網絡請求的時候加載小菊花,請求成功加載出 ListView.

可以看得出來 FutureBuilder 确實是非常友善,而且我們可以自己封裝幾個控件,後面用的時候就會更加完美。