注意:无特殊说明,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,
          ),
        );
      },
    );

效果如下:

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

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

效果如下:

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

效果如下:

模拟网络加载失败:

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

效果如下:

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

这才是正确的用法。

更多相关阅读:

如果这篇文章有帮助到您,希望您来个“赞”并关注我的公众号,非常谢谢。

Flutter Widgets 之 FutureBuilder的更多相关文章

  1. 【Flutter Widgets大全】电子书开源

    [Flutter Widgets大全]是老孟耗费大量精力整理的,总共有330多个组件的详细用法,开源到Github上,希望可以帮助到大家,开源不易,点个赞可不可以. [Flutter Widgets ...

  2. Flutter Widgets 之 InkWell 和 Ink

    注意:无特殊说明,Flutter版本及Dart版本如下: Flutter版本: 1.12.13+hotfix.5 Dart版本: 2.7.0 InkWell InkWell组件在用户点击时出现&quo ...

  3. Flutter Widgets 之 BottomNavigationBar 和 BottomNavigationBarItem

    注意:无特殊说明,Flutter版本及Dart版本如下: Flutter版本: 1.12.13+hotfix.5 Dart版本: 2.7.0 BottomNavigationBar 和 BottomN ...

  4. Flutter Widgets 之 ListWheelScrollView

    注意:无特殊说明,Flutter版本及Dart版本如下: Flutter版本: 1.12.13+hotfix.5 Dart版本: 2.7.0 基础用法 在展示大量数据的时候我们第一会想到使用ListV ...

  5. Flutter Widgets 之 RichText

    注意:无特殊说明,Flutter版本及Dart版本如下: Flutter版本: 1.12.13+hotfix.5 Dart版本: 2.7.0 基础用法 应用程序离不开文字的展示,因此文字的排版非常重要 ...

  6. Flutter Widgets 之 SnackBar

    注意:无特殊说明,Flutter版本及Dart版本如下: Flutter版本: 1.12.13+hotfix.5 Dart版本: 2.7.0 基础用法 应用程序有时候需要弹出消息提示用户,比如'网络连 ...

  7. Flutter Widgets 对话框-Dialog

    注意:无特殊说明,Flutter版本及Dart版本如下: Flutter版本: 1.12.13+hotfix.5 Dart版本: 2.7.0 当应用程序进行重要操作时经常需要用户进行2次确认,以避免用 ...

  8. Flutter Widgets

    Flutter Widgets Flutter 组件 Syncfusion Flutter Widgets 所有组件均支持即装即用的 Android,iOS和 Web not free https:/ ...

  9. Flutter Widgets (Container/Row/Column/Image)

    俗话说知己知彼百战百胜,如果对Flutter 里面的各种Widgets不了解,那你就别想将它们组合成你想要的效果.从今天开始.会把一个一个的widget 撸一遍..知道它大概的用法.效果.当你想做某个 ...

随机推荐

  1. 关于idea修改当前使用的git账户的问题

    原文地址:https://www.cnblogs.com/xuxiaojian/p/8890656.html 1.问题描述: 由于前一段时间公司迁移git,就是将项目代码等迁移到另一个git服务器上, ...

  2. Spring-事务(1)

    一,注解的方式实现事务 1.Dao层 package com.atguigu.spring.tx; public interface BookShopDao { //根据书号获取书的单价 public ...

  3. jmeter使用—正则表达式提取器

    当我们测试接口的时候,有些请求参数是需要从上个接口返回获取的数据,这样的话我们就需要用到关联了.今天我们使用的关联是正则表达式提取器来进行获取需要关联的数据. 下面来具体说明正则表达式提取器的使用方法 ...

  4. ASP.NET Core下Ocelot的简单使用

    一.创建demo项目 1.新建webapi项目,命名为“DemoProject”,去掉HTTPS勾选 using Microsoft.AspNetCore.Mvc; using System.Coll ...

  5. 02--java--环境搭建

    第一步,下载JDK 去ORACLE官网http://www.oracle.com下载 有安装版和绿色版,安装版一路下一步,绿色版解压缩压缩包就行了 安装版直接自动配置环境变量,绿色版需要自己配置环境变 ...

  6. tf.keras遇见的坑:Output tensors to a Model must be the output of a TensorFlow `Layer`

    经过网上查找,找到了问题所在:在使用keras编程模式是,中间插入了tf.reshape()方法便遇到此问题. 解决办法:对于遇到相同问题的任何人,可以使用keras的Lambda层来包装张量流操作, ...

  7. linux--->阿里云centos6.9安装yii2报错

    阿里云centos6.9安装yii2报错 错误显示:Warning: require(/vendor/autoload.php): failed to open stream: No such fil ...

  8. Kafka系列1:Kafka概况

    Kafka系列1:Kafka概况 Kafka是当前分布式系统中最流行的消息中间件之一,凭借着其高吞吐量的设计,在日志收集系统和消息系统的应用场景中深得开发者喜爱.本篇就聊聊Kafka相关的一些知识点. ...

  9. Java基于OpenCV实现走迷宫(图片+路线展示)

    Java基于OpenCV实现走迷宫(图片+路线展示) 由于疫情,待在家中,太过无聊.同学发了我张迷宫图片,让我走迷宫来缓解暴躁,于是乎就码了一个程序出来.特此记录. 原图: 这张图,由于不是非常清晰, ...

  10. HTTP权威指南之URL与资源

    前言 web基础中介绍了URI.URL与URN: URI是一类更通用的资源标识符,URL是它的一个子集: URI是一个通用的概念,它主要由URL与URN组成: URL是通过描述资源的位置来标识资源的, ...