Flutter FutureBuilder+Dio异步调用心得

Future用了一段时间,异步和序列化还有网络这块真的是头大,现在算搞明白了点。
FutureBuilder 要想实现Dio网络请求完成后再加载,必须DIO要返回Response对象才行,不然FutureBuilder拿不到异常,失败了他也不知道,DIO就简单封装一下把URL地址和请求的参数封一下就可以了,返回必须是Response,不要画蛇添足加try catch之类的,有异常DIO在非调试模式下不会抛出来,加了反而起反作用,这个问题研究了三天才整明白,切记。
Flutter FutureBuilder+Dio异步调用心得_第1张图片
Flutter FutureBuilder+Dio异步调用心得_第2张图片
Flutter FutureBuilder+Dio异步调用心得_第3张图片
Flutter FutureBuilder+Dio异步调用心得_第4张图片
Flutter FutureBuilder+Dio异步调用心得_第5张图片
最后在无连接时的效果
Flutter FutureBuilder+Dio异步调用心得_第6张图片

上代码:
主要解决页面进入时要异步读完数据再渲染页面的问题
//初始化获取数据

     @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(),
              ],
            ),
          )
        ],
      ),
    );
  }

你可能感兴趣的:(Flutter FutureBuilder+Dio异步调用心得)