IT教程 ·

Flutter Widgets 之 FutureBuilder

ResNet详解与分析

 

注重:无特别申明,Flutter版本及Dart版本以下:

  • Flutter版本: 1.12.13+hotfix.5
  • Dart版本: 2.7.0

展现异步使命状况

当有一个Future(异步)使命须要展现给用户时,能够运用FutureBuilder控件来完成,比方向服务器发送数据胜利时显现胜利提醒:

var _future = Future.delayed(Duration(seconds: 3), () {
    return '老孟,一个有立场的程序员';
  });

FutureBuilder(
      future: _future,
      builder: (context, snapshot) {
        var widget;
        if (snapshot.connectionState == ConnectionState.done) {
          if (snapshot.hasError) {
            widget = Icon(
              Icons.error,
              color: Colors.red,
              size: 48,
            );
          } else {
            widget = Icon(
              Icons.check_circle,
              color: Colors.green,
              size: 36,
            );
          }
        } else {
          widget = Padding(
            padding: EdgeInsets.all(20),
            child: CircularProgressIndicator(),
          );
        }

        return Center(
          child: Container(
            height: 100,
            width: 100,
            decoration: BoxDecoration(
                border: Border.all(color: Colors.grey),
                borderRadius: BorderRadius.all(Radius.circular(10))),
            child: widget,
          ),
        );
      },
    );

结果以下:

Flutter Widgets 之 FutureBuilder IT教程 第1张

在Future使命中出现异常怎样处置惩罚,下面模仿出现异常,修正_future:

var _future = Future.delayed(Duration(seconds: 3), () {
    return Future.error('');
  });

结果以下:

Flutter Widgets 之 FutureBuilder IT教程 第2张

builder是FutureBuilder的构建函数,在这里能够推断状况及数据显现差别的UI,
ConnectionState的状况包括四种:nonewaitingactivedone,但我们只须要关注done状况,此状况示意Future实行完成,snapshot参数的范例是AsyncSnapshot<T>

ListView加载收集数据

FutureBuilder另有一个比较经常使用的场景:收集加载数据并列表展现,这是一个异常罕见的功用,在收集要求过程当中显现loading,要求失利时显现失利UI,胜利时显现胜利UI。

模仿胜利收集要求,通常会返回json字符串:

var _future = Future.delayed(Duration(seconds: 3), () {
    return 'json 字符串';
  });

构建FutureBuilder控件:

FutureBuilder(
      future: _future,
      builder: (context, snapshot) {
        var widget;
        if (snapshot.connectionState == ConnectionState.done) {
          if (snapshot.hasError) {
            widget = _loadingErrorWidget();
          } else {
            widget = _dataWidget(snapshot.data);
          }
        } else {
          widget = _loadingWidget();
        }
        return widget;
      },
    );

构建loading控件:

_loadingWidget() {
    return Center(
      child: Padding(
        padding: EdgeInsets.all(20),
        child: CircularProgressIndicator(),
      ),
    );
  }

构建收集加载失利控件:

_loadingErrorWidget() {
    return Center(
      child: Text('数据加载失利,请重试。'),
    );
  }

数据加载胜利,构建数据展现控件:

_dataWidget(data) {
    return ListView.separated(
      itemBuilder: (context, index) {
        return Container(
          height: 60,
          alignment: Alignment.center,
          child: Text(
            '$index',
            style: TextStyle(fontSize: 20),
          ),
        );
      },
      separatorBuilder: (context, index) {
        return Divider();
      },
      itemCount: 10,
    );
  }

结果以下:

Flutter Widgets 之 FutureBuilder IT教程 第3张

模仿收集加载失利:

var _future = Future.delayed(Duration(seconds: 3), () {
    return Future.error('');
  });

结果以下:

Flutter Widgets 之 FutureBuilder IT教程 第4张

经由过程上面的示例申明FutureBuilder控件极大的简化了异步使命相干显现的控件,不再须要开发者本身保护种种状况以及更新时挪用State.setState

防备FutureBuilder重绘

FutureBuilder是一个StatefulWidget控件,假如在FutureBuilder控件节点的父节点重绘rebuild,那末FutureBuilder也会重绘,这不仅斲丧不必要的资本,假如是收集要求还会斲丧用户的流量,这是异常蹩脚的体验,怎样处理这个问题?

经由过程源代码发明FutureBuilder重绘逻辑是如许的:

@override
  void didUpdateWidget(FutureBuilder<T> oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (oldWidget.future != widget.future) {
      if (_activeCallbackIdentity != null) {
        _unsubscribe();
        _snapshot = _snapshot.inState(ConnectionState.none);
      }
      _subscribe();
    }
  }

FutureBuilder在重修时推断旧的future和新的future是不是相称,假如不相称才会重修,所以我们只须要让其相称即可,有人可能会认为设置的future是同一个函数,以下:

 _future() async{
    ...
  }

FutureBuilder(
    future: _future(),
    ...
)

上面的体式格局是不相称的,是毛病的用法,能够将_future要领赋值给变量:

var _mFuture;

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    _mFuture = _future();
  }

 _future() async{
    ...
  }

FutureBuilder(
    future: _mFuture,
    ...
)

这才是准确的用法。

更多相干浏览:

假如这篇文章有协助到您,愿望您来个“赞”并关注我的民众号,异常感谢。

《程序员的办公室日常》第一回 相识

参与评论