在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),
],
),
);
}
}
複製代碼