Future用了一段时间,异步和序列化还有网络这块真的是头大,现在算搞明白了点。
FutureBuilder 要想实现Dio网络请求完成后再加载,必须DIO要返回Response对象才行,不然FutureBuilder拿不到异常,失败了他也不知道,DIO就简单封装一下把URL地址和请求的参数封一下就可以了,返回必须是Response,不要画蛇添足加try catch之类的,有异常DIO在非调试模式下不会抛出来,加了反而起反作用,这个问题研究了三天才整明白,切记。
最后在无连接时的效果
上代码:
主要解决页面进入时要异步读完数据再渲染页面的问题
//初始化获取数据
@override
initState() {
print('初始化ReserveView');
reserveStatMenu = Common.reserveStatMenu;
reserveTypeMenu = Common.reserveTypeMenu;
reserveFloorMenu = Common.reserveFloorMenu;
//获取数据
_futureBuilderFuture = getData();
super.initState();
}
获取数据方法,这里加了个延时1秒,主要方便动画效果显示更明显,查询太快不延时一闪而过,根本看不到转圈
Future getData() async {
await Future.delayed(Duration(seconds: 1), () {
print("延时1秒后请求数据");
});
Response response = await ReserveNet().getReserveHttpRequest(
Common.reserveStatSelectValue,
Common.reserveTypeSelectValue,
Common.reserveFloorSelectValue,
Common.reserveCashedSelectValue);
return response;
}
定义futureBuilder方法
var _futureBuilderFuture;
//FutureBuild异步接收
Widget reserveFutureBuild(BuildContext context, AsyncSnapshot snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
return showFutureMsg('还没开始网络请求');
case ConnectionState.active:
return showFutureMsg('连接激活');
case ConnectionState.waiting:
return Center(
child: CircularProgressIndicator(),
);
case ConnectionState.done:
if (snapshot.hasError) {
return showFutureMsg(DioUtils.formatError(snapshot.error));
} else {
Response response = snapshot.data;
var map = jsonDecode(response.data);
ResponseModel result = ResponseModel.fromJson(map);
//成功
if (result.errCode == 1) {
//内容反序列化
ReserveModel reserveModel =
ReserveModel.fromJson(jsonDecode(result.content));
//存入公共变量
Common.reserveDatas = reserveModel;
}
//执行我的渲染方法
return ReserveSumAndList();
}
break;
default:
return null; //由于我的渲染是个有状态控件,他要求返回一个Widgent,所以加了这句,程序其实走不到这里
}
}
另外单独封了个显示的框框 showFutureMsg
Widget showFutureMsg(String msg) {
return Center(
child: Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
padding: EdgeInsets.only(left: 2, top: 2, bottom: 2),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(4)), //圆角
boxShadow: [
//阴影效果
BoxShadow(
color: Colors.black26,
offset: Offset(2, 2),
blurRadius: 1,
spreadRadius: 0.5)
],
color: Colors.blue,
border: Border.all(width: 0.0, style: BorderStyle.none),
),
child: Container(
height: 80,
width: 200,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
msg, //消息文本
style: TextStyle(color: Colors.white),
),
]),
),
),
],
),
));
}
最后接到要渲染的地方 我放在Builder下边
@override
Widget build(BuildContext context) {
return new DefaultDropdownMenuController(
onSelected: ({int menuIndex, int index, int subIndex, dynamic data}) {
print('Reserve菜单改变');
switch (menuIndex) {
case 0:
Common.reserveStatSelectValue =
reserveStatMenu[index]['title'].toString();
Common.reserveStatSelectIndex = index; //保存索引
break;
case 1:
Common.reserveTypeSelectValue =
reserveTypeMenu[index]['title'].toString();
Common.reserveTypeSelectIndex = index; //保存索引
break;
case 2:
Common.reserveFloorSelectValue =
reserveFloorMenu[index]['title'].toString();
Common.reserveFloorSelectIndex = index; //保存索引
break;
case 3:
Common.reserveCashedSelectValue =
reserveCashedMenu[index]['title'].toString();
Common.reserveCashedSelectIndex = index; //保存索引
break;
default:
break;
}
print(Common.reserveStatSelectValue +
Common.reserveTypeSelectValue +
Common.reserveFloorSelectValue +
Common.reserveCashedSelectValue);
//发送广播给订阅者
eventBus.fire(EventReserveMenuChange('Menu改变'));
},
child: Column(
children: [
buildDropdownHeader(),
new Expanded(
child: new Stack(
children: [
//预订数据渲染
FutureBuilder(
future: _futureBuilderFuture,
builder: reserveFutureBuild,
),
//渲染下拉菜单
buildDropdownMenu(),
],
),
)
],
),
);
}