Flutter Widgets 之 FutureBuilder_flutter snapshot-程序员宅基地

技术标签: 【Flutter点滴知识 】  

展示异步任务状态

当有一个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,
          ),
        );
      },
    );

效果如下:

image

在Future任务中出现异常如何处理,下面模拟出现异常,修改_future:

 

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

效果如下:

image

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

效果如下:

image

模拟网络加载失败:

 

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

效果如下:

image

通过上面的示例说明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,
    ...
)

这才是正确的用法。

更多相关阅读:



作者:老孟程序员
链接:https://www.jianshu.com/p/1519ca655c7f
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/sinat_17775997/article/details/106442385

智能推荐

k-means聚类算法原理与参数调优详解_kmeans聚类算法-程序员宅基地

文章浏览阅读4.2w次,点赞26次,收藏223次。https://www.toutiao.com/a6690435044869145101/k-means算法原理K-means中心思想:事先确定常数K,常数K意味着最终的聚类类别数,首先随机选定初始点为质心,并通过计算每一个样本与质心之间的相似度(这里为欧式距离),将样本点归到最相似的类中,接着,重新计算每个类的质心(即为类中心),重复这样的过程,直到质心不再改变,最终就确定了每个样..._kmeans聚类算法

海康威视部分综合安防管理平台产品存在任意文件上传漏洞_海康威视综合安防管理平台任意文件上传漏洞-程序员宅基地

文章浏览阅读1.3k次。海康威视部分综合安防管理平台历史版本由于对上传文件接口校验不足,攻击者可以将恶意文件上传到平台,导致获取服务权限或服务异常。攻击者利用该漏洞上传Webshell,并随后执行任意命令,对主机上相关文件进行加密,加密后缀为locked1。海康威视iVMS集中监控应用管理平台,是以安全防范业务应用为导向,以视频图像应用为基础手段,综合视频监控、联网报警、智能分析、运维管理等多种安全防范应用系统,构建的多业务应用综合管理平台。(2)建立重要业务数据的定期备份机制,并做好权限隔离,防止勒索软件对备份数据进行加密;_海康威视综合安防管理平台任意文件上传漏洞

socket.io emit callback调用探秘-程序员宅基地

文章浏览阅读436次。socket.iohttps://socket.io/https://socket.io/docs/What Socket.IO isSocket.IO is a library that enables real-time, bidirectional and event-based communication between the browser and the s..._socket.io callback

Linux安装mpp数据库(Greenplum 集群部署)_用linux连接mpp数据库插入数据-程序员宅基地

文章浏览阅读1.3k次。下载greenplum-db-5.23.0-rhel7-x86_64.bin安装包个人百度网盘地址:链接:https://pan.baidu.com/s/1YCIo9vS0fSfi6pHwDLL5KQ 提取码:jmr6简单记录一下安装mpp(greenplum)的过程,以及遇到的问题。不喜勿喷简单来说GPDB是一个分布式数据库软件,其可以管理和处理分布在多个不同主机上的海量数据。对于GPDB来说,一个DB实例实际上是由多个独立的PostgreSQL实例组成的,它们分布在不同的物理主机上,协同工作,呈_用linux连接mpp数据库插入数据

docker api未授权导致rce 漏洞修复_docker未授权访问漏洞怎么修复-程序员宅基地

文章浏览阅读1.3k次。docker api未授权导致rce 漏洞修复_docker未授权访问漏洞怎么修复

设计模式-30-中介模式-行为型模式-程序员宅基地

文章浏览阅读673次,点赞30次,收藏10次。现在,我们来学习23种经典设计模式中的最后一个,中介模式。跟前面刚刚讲过的命令模式、解释器模式类似,中介模式也属于不怎么常用的模式,应用场景比较特殊、有限,但是,跟它俩不同的是,中介模式理解起来并不难,代码实现也非常简单,学习难度要小很多。如果你对中介模式有所了解,你可能会知道,中介模式跟之前讲过的观察者模式有点相似,所以,今天我们还会详细讨论下这两种模式的区别。

随便推点

vue3 antd pro 框架动态路由_vue3+ant design + ts+pro-程序员宅基地

文章浏览阅读629次。1. 在store/user.ts中,找到 GENERATE_ROUTES_DYNAMIC 方法中调用的方法:generatorDynamicRouter(),此方法在在router/router-guards/router-guards.ts中。2. router/router-guards/router-guards.ts中,通过方法getCurrentUserNav(),获取到个人信息中的菜单,将菜单列表传generator()方法中,此方法将菜单列表处理成路由所需格式的路由数组。_vue3+ant design + ts+pro

【华为云技术分享】敏捷开发落地不实际?原因可能在于你的 IDE 工具_华为云ide问题-程序员宅基地

文章浏览阅读3.5k次。对于企业来说,效率就是一切。开发效率的工程化建设已经开始被各大企业提到技术管理日程中。而且现阶段,无论是框架也好、模板也好,目的都是在为提升代码开发效率而努力。随着云计算的深入,端 + 云的开发模式以及完全云端化的开发模式都先后上线,这些无疑都是在对传统 IDE 开发模式的挑战。云端 IDE,会是未来的趋势吗?云时代下,万物上云正在影响企业研发效率工程化建设万物上云,可以说已经是不可逆..._华为云ide问题

数据库基础,进阶_数据库进阶知识包括哪些-程序员宅基地

文章浏览阅读223次。名称全称简称数据库存储数据的仓库,数据是有组织的进行存储数据库管理系统操纵和管理数据库的大型软件SQL操作关系型数据库的编程语言,定义了一套操作关系型数据库的统一标准主流的关系型数据库管理系统Oracle 收费昂贵MySQL 免费SQLserverPostgreSQL将一列数据作为一个整体,进行纵向计算概念:约束是作用于表中字段上的规则,用于限制存储在表中的数据。目的:保证数据库中数据的正确、有效性和完整性,统一性。约束描述关键字非空约束。_数据库进阶知识包括哪些

layui字体图标 loading图标静止不旋转_layui加载动画不会转圈-程序员宅基地

文章浏览阅读2.8k次,点赞3次,收藏2次。layui的字体图标库提供了丰富的字体图标,其中还有动态的loading图,但如果按照添加其他图标一样将class样式复制到按钮上,却发现loading图并不会旋转。_layui加载动画不会转圈

SAP 人力资源工资配置项2---工资类型配置_sap人员子类别如何对应工资等级-程序员宅基地

文章浏览阅读5.1k次。sap中使用工资等级管理工资_sap人员子类别如何对应工资等级

郑州大学算法设计与分析实验4-程序员宅基地

文章浏览阅读1.2k次,点赞21次,收藏20次。【代码】郑州大学算法设计与分析实验4。

推荐文章

热门文章

相关标签