前言
很多時候會依賴一些異步數據來動態更新UI,比如在打開一個頁面時我們需要先從互聯網上獲取數據,在獲取數據的過程中我們顯示一個加載框,等獲取到數據時我們再渲染頁面;又比如想展示Stream(比如文件流、互聯網數據接收流)的進度。當然,通過StatefulWidget完全可以實現上述這些功能。但由於在實際開發中依賴異步數據更新UI的這種場景非常常見,因此Flutter專門提供了FutureBuilder和StreamBuilder兩個組件來快速實現這種功能。
接口描述
FutureBuilder會依賴一個Future,它會根據所依賴的Future的狀態來動態構建自身。描述如下:
FutureBuilder({
// FutureBuilder依賴的Future,通常是一個異步耗時任務
this.future,
// 初始數據,用戶設置默認數據
this.initialData,
// Widget構建器,該構建器會在Future執行的不同階段被多次調用
// 構建器簽名為:Function(BuildContext context, AsyncSnapshot snapshot)
// snapshot會包含當前異步任務的狀態信息及結果信息,比如可以通過snapshot.connectionState獲取異步任務的狀態信息,通過snapshot.hasError判斷任務時候有錯誤等
@required this.builder,
})
StreamBuilder({
Key key,
this.initialData,
Stream<T> stream,
@required this.builder,
})
代碼示例
// 異步UI更新(FutureBuilder\StreamBuilder)
import 'dart:math';
import 'package:flutter/material.dart';
// 實現一個路由,當該路由打開時我們從網上獲取數據,獲取數據時彈一個加載框;獲取結束時,如果成功則顯示獲取到的數據,如果失敗則顯示錯誤。
// 不真正去網絡請求數據,而是模擬一下這個過程,隔3秒后返回一個字符串
Future<String> mockNetworkData() async{
return Future.delayed(Duration(seconds: 2), () => "我是從互聯網上獲取的數據!");
}
class FutureBuilderTest extends StatelessWidget{
@override
Widget build(BuildContext context){
return Center(
child: FutureBuilder<String>(
future: mockNetworkData(),
builder: (BuildContext context, AsyncSnapshot snapshot){
// 請求已結束
if(snapshot.connectionState == ConnectionState.done){
if(snapshot.hasError){
// 請求失敗,顯示錯誤
return Text("Error: ${snapshot.error}");
}else{
// 請求成功,顯示數據
return Text("Contents: ${snapshot.data}");
}
}else{
// 請求未結束,顯示loading
return CircularProgressIndicator();
}
},
),
);
}
}
// 創建一個計時器的示例:每隔1秒,計數加1。這里,使用Stream來實現每隔一秒生成一個數字。
Stream<int> counter(){
return Stream.periodic(Duration(seconds: 1), (i){
return i;
});
}
class StreamBuilderTest extends StatelessWidget{
@override
Widget build(BuildContext context){
return StreamBuilder<int>(
stream: counter(),
builder: (BuildContext context, AsyncSnapshot<int> snapshot){
if(snapshot.hasError)
return Text("Error: ${snapshot.error}");
switch(snapshot.connectionState){
case ConnectionState.none:
return Text("沒有Stream");
case ConnectionState.waiting:
return Text("等待數據...");
case ConnectionState.active:
// TODO: Handle this case.
return Text("active:${snapshot.data}");
case ConnectionState.done:
// TODO: Handle this case.
return Text("Stream已關閉");
}
return null;
},
);
}
}
總結
Dart中Stream 也是用於接收異步事件數據,和Future 不同的是,它可以接收多個異步操作的結果,它常用於會多次讀取數據的異步任務場景,如網絡內容下載、文件讀寫等。StreamBuilder正是用於配合Stream來展示流上事件(數據)變化的UI組件。在實戰中,凡是UI會依賴多個異步數據而發生變化的場景都可以使用StreamBuilder。