基于FutureBuilder通用网络请求界面封装
Dart异步编程Future
在Dart中,处理异步有两种方式,一种方式是asyn/awiat ,另一种方式就是FutureBuilder,FutureBuilder能够在网络请求开始前,请求中,请求完成or失败,帮助我们管理我们的UI界面。
FlutterBuilder源码
///构造方法以及对应参数类型
const FutureBuilder({
Key key,
this.future,
this.initialData,
@required this.builder,
}) : assert(builder != null), super(key: key);
final Future future; //获取数据异步操作
final AsyncWidgetBuilder 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简单使用Demo
FutureBuilder(
future: fetchPost(),//网络请求操作
builder:
(BuildContext context, AsyncSnapshot 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: [
Text(
"网络数据返回",
style: TextStyle(fontSize: 20),
),
Text("title:${snapshot.data.title}"),
Text("icon:${snapshot.data.icon}"),
Text("url:${snapshot.data.url}"),
],
);
}
}
})
FutureBuilder简单封装
接下来开始我们的通用网络Widget封装,根据Demo我们发现需要一个可以返回Future
框架思考需要实现功能:
- 请求网络的方法 loadData
- 数据正常返回,给Widget界面赋值;
- 加载error Widget,网络错误or无网状态下,点击错误Widget重新触发网络请求;
- 提供默认的loading 以及 error Widget,同时用户也可自定义想要的提示界面;
开始实现功能
1.定义传递请求方法
///FutureBuilder的future传的内容
typedef LoadDataFuture = Future Function(BuildContext context);
2.定义抽象类(数据正常展示Widget)
abstract class NetNormalWidget 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.开始拼装框架
///定义该框架需要属性实现对应State
class FutureBuilderWidget extends StatefulWidget {
final Widget loadingWidget;
final Widget errorWidget;
final NetNormalWidget commonWidget;
final LoadDataFuture loadData;
FutureBuilderWidget(
{@required this.commonWidget,
@required this.loadData,
this.loadingWidget,
this.errorWidget});
@override
State createState() => _FutureBuilderWidgetState();
}
///实现State方法并mixins网络出错点击回调
class _FutureBuilderWidgetState extends State>
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 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 createState() => _FutureBuilderState();
}
class _FutureBuilderState extends State with ErrorCallback{
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("FutureBuilder控件封装"),
),
body: FutureBuilderWidget(
commonWidget: CommonWidget(),
loadData: _loadData,
//自定义出错界面以及对应店家回调事件(本例子直接关闭界面)
// errorWidget: NetErrorWidget(
// callback:this,
// errorChild: Center(
// child: Text("网络出错 点击返回"),
// ),
// ),
),
);
}
///网络请求库
Future _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 {
@override
Widget buildContainer(CommonModel t) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(t.title),
Text(t.icon),
],
),
);
}
}