在Dart中,處理異步有兩種方式,一種方式是asyn/awiat ,另外一種方式就是FutureBuilder,FutureBuilder可以在網絡請求開始前,請求中,請求完成or失敗,幫助咱們管理咱們的UI界面。github
///構造方法以及對應參數類型 const FutureBuilder({ Key key, this.future, this.initialData, @required this.builder, }) : assert(builder != null), super(key: key); final Future<T> future; //獲取數據異步操做 final AsyncWidgetBuilder<T> builder;//根據狀態返回不一樣widget ///ConnectionState四種狀態 enum ConnectionState { /// Not currently connected to any asynchronous computation. /// For example, a [FutureBuilder] whose [FutureBuilder.future] is null. none, /// Connected to an asynchronous computation and awaiting interaction. waiting, /// Connected to an active asynchronous computation. /// For example, a [Stream] that has returned at least one value, but is not /// yet done. active, /// Connected to a terminated asynchronous computation. done, } 複製代碼
FutureBuilder( future: fetchPost(),//網絡請求操做 builder: (BuildContext context, AsyncSnapshot<CommonModel> snapshot) { switch (snapshot.connectionState) { case ConnectionState.none: return Text("Input a url to connect"); case ConnectionState.waiting: //圓形加載widget return Center(child: CircularProgressIndicator()); case ConnectionState.active: return Text(""); case ConnectionState.done: if (snapshot.hasError) { return Text( "${snapshot.error}", style: TextStyle(color: Colors.red), ); } else { //正常數據返回回調 return Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Text( "網絡數據返回", style: TextStyle(fontSize: 20), ), Text("title:${snapshot.data.title}"), Text("icon:${snapshot.data.icon}"), Text("url:${snapshot.data.url}"), ], ); } } }) 複製代碼
接下來開始咱們的通用網絡Widget封裝,根據Demo咱們發現須要一個能夠返回Future網絡請求方法,加載界面Widget,加載出錯的Widgwt以及網絡請求結束正常展現數據Widget。編程
框架思考須要實現功能:json
1.定義傳遞請求方法redux
///FutureBuilder的future傳的內容 typedef LoadDataFuture<T> = Future<T> Function(BuildContext context); 複製代碼
2.定義抽象類(數據正常展現Widget)markdown
abstract class NetNormalWidget<T> extends StatelessWidget { final T bean;//通用數據類 NetNormalWidget({this.bean}); @override Widget build(BuildContext context) { return buildContainer(bean); } ///給定義Widget賦值 Widget buildContainer(T t); } 複製代碼
3.定義網絡出錯Widget以及對應點擊回調網絡
///net出錯 回調 abstract class ErrorCallback { void retryCall(); } ///網絡請求 失敗 Widget class NetErrorWidget extends StatelessWidget { final Widget errorChild; final ErrorCallback callback; NetErrorWidget({@required this.errorChild, this.callback}); @override Widget build(BuildContext context) { return GestureDetector( child: errorChild, onTap: () => callback?.retryCall(), ); } } 複製代碼
4.開始拼裝框架app
///定義該框架須要屬性實現對應State class FutureBuilderWidget<T> extends StatefulWidget { final Widget loadingWidget; final Widget errorWidget; final NetNormalWidget<T> commonWidget; final LoadDataFuture<T> loadData; FutureBuilderWidget( {@required this.commonWidget, @required this.loadData, this.loadingWidget, this.errorWidget}); @override State<StatefulWidget> createState() => _FutureBuilderWidgetState<T>(); } ///實現State方法並mixins網絡出錯點擊回調 class _FutureBuilderWidgetState<T> extends State<FutureBuilderWidget<T>> with ErrorCallback { @override void initState() { super.initState(); widget.loadData(context); } ///默認加載界面 final defaultLoading = Center( child: CircularProgressIndicator(), ); ///默認出錯界面 Widget _defaultError(dynamic error) { return Center( child: Text(error.toString()), ); } @override Widget build(BuildContext context) { return FutureBuilder( future: widget.loadData(context), builder: (BuildContext context, AsyncSnapshot<T> snapshot) { switch (snapshot.connectionState) { case ConnectionState.none: break; case ConnectionState.waiting: case ConnectionState.active: return widget.loadingWidget ?? defaultLoading; case ConnectionState.done: if (snapshot.hasError) { ///網絡出錯 if (widget.errorWidget != null) { ///自定義出錯界面 if (widget.errorWidget is NetErrorWidget) { return widget.errorWidget; } else { ///只自定義界面顯示內容 return NetErrorWidget( errorChild: widget.errorWidget, callback: this, ); } } else { ///選用默認出錯界面 return NetErrorWidget( errorChild: _defaultError(snapshot.error), callback: this, ); } } return widget.commonWidget.buildContainer(snapshot.data); } }); } @override void retryCall() { widget.loadData(context); setState(() { ///通知State從新構建界面須要 }); } } 複製代碼
class FutureBuilderDemo extends StatefulWidget { @override State<StatefulWidget> createState() => _FutureBuilderState(); } class _FutureBuilderState extends State<FutureBuilderDemo> with ErrorCallback{ @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("FutureBuilder控件封裝"), ), body: FutureBuilderWidget<CommonModel>( commonWidget: CommonWidget(), loadData: _loadData, //自定義出錯界面以及對應店家回調事件(本例子直接關閉界面) // errorWidget: NetErrorWidget( // callback:this, // errorChild: Center( // child: Text("網絡出錯 點擊返回"), // ), // ), ), ); } ///網絡請求庫 Future<CommonModel> _loadData(BuildContext context) async { Api.baseUrl = 'http://www.devio.org/io/flutter_app/'; final resp = await HttpUtil.instance.fetchGet('json/test_common_model.json'); return CommonModel.fromJson(resp); } @override void retryCall() { Navigator.of(context).pop(); } } ///實現抽象方法,直接給界面複製 class CommonWidget extends NetNormalWidget<CommonModel> { @override Widget buildContainer(CommonModel t) { return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Text(t.title), Text(t.icon), ], ), ); } } 複製代碼