Flutter 异步操作

这篇具有很好参考价值的文章主要介绍了Flutter 异步操作。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

在Flutter中,借助 FutureBuilder 组件和 StreamBuilder 组件,可以非常方便地完成异步操作。

一、FutureBuilder

在讲解FutureBuilder之前,你首先要知道Future是什么,了解了这个,后面再了解该组件就轻松许多。
在不同的编程语言中会有不同的名词来定义,在Dart语言中 选择使用Future类型配合async、await关键字来实现异步支持。
Future 表示一个现在不确定,但以后应该可以确定的值。这个值可以是任意类型,如 Future<int>表示一个未来获取到的整型值,Future<String>表示一个未来获取到的字符串。
我们通常会在定时器、网络请求中使用Future,它会有三种状态:uncompleted(未完成)、completed with data(获取到一个数据)、completed with error(捕获到一个错误),所以在实战过程中,我们需要根据这三种状态来判断当前界面应该是怎样的,加载中、数据正常显示、提示错误 重新操作。

小示例:

定义一个getValue方法:

Future<String> getValue() async {
    await Future.delayed(Duration(seconds: 3));
    return "100";
}

结合FutureBuilder组件来调用方法:

FutureBuilder(
  future: getValue(),
   builder:
       (BuildContext context, AsyncSnapshot<String> snapshot) {
     if (snapshot.hasData) {
       return Text(
           "${snapshot.data}",
           style: TextStyle(fontSize: 30, fontWeight: FontWeight.bold),
         );
     } else if (snapshot.hasError) {
       return Text("${snapshot.error}");
     } else {
       return Container(
         height: 50,
         width: 50,
         margin: EdgeInsets.only(top: 10),
         child: CircularProgressIndicator(
           strokeWidth: 8.0,
         )
       );
     }
   }),

Flutter 异步操作
我们逐步来分解上面的示例代码:

  1. 这里使用async关键字将函数标为异步函数,这样函数的返回值就会被封装为异步。
  2. FutureBuilder组件的future属性是此组件的必传参数。FutureBuilder组件得到future之后,便开始通过future的then等方法追踪它(监听future执行的结果),当其状态改变时自动调用builder函数重绘。
  3. builder函数。每次绘制时,FutureBuilder都会调用这里的builder回传函数,并提供BuildContext(上下文)和AsyncSnapshot<>(异步快照)。在这里AsyncSnapshot<> 封装的类型就是future参数里的Future<> 所封装的类型。像上例一样,Future返回一个String,那么对应的AsyncSnapshot也是String类型。
  4. AsyncSnapshot 中含有 Future的最新状态及被封装的数据或异常。另外ConnectionState 属性描述了 Future 的四种状态,其分别为 none、waiting、active、done。
  5. 大多数时间做异步操作都是为了获取最终的数据,那么这个数据的获取即是在Future的done(完成)之后,所以我们的逻辑代码可以这样写。
FutureBuilder(
   future: getValue(),
   builder:
       (BuildContext context, AsyncSnapshot<String> snapshot) {
     if(snapshot.connectionState == ConnectionState.done) {
       if (snapshot.hasData) {
         return Text(
           "${snapshot.data}",
           style: TextStyle(fontSize: 30, fontWeight: FontWeight.bold),
         );
       } else {
         return Text("${snapshot.error}");
       }
     }else {
       return Container(
           height: 50,
           width: 50,
           margin: const EdgeInsets.only(top: 10),
           child: const CircularProgressIndicator(
             strokeWidth: 8.0,
           )
       );
     }
   }),

首先判断Future的状态是否完成,未完成的情况下就加载动画组件。加载完成的情况下再进行判断snapshot返回的是正确数据还是异常,此时data和error必有一个且只有一个不是空。

总结一下:在Future完成之前,data和error都为空,Future完成之后,data和error有且仅有一个为空。所以这个时候我们可以不检查Future的状态是否完成,而是直接通过snapshot的hasData数据和hasError异常来判断。如果既没有数据又没有异常,那就是当前的Future还未完成,可直接返回加载动画组件。这个时候的代码就如最开始的那个示例一样直接检查hasData和hasError。

初始值 initialData

在Future完成之前,initialData属性提供一个数据的初始值给FutureBuilder组件使用。在有初始值的情况下,Future完成之前hasData会返回true,并且data中存储着所设置的初始值。当Future完成之后,FutureBuilder组件会自动切换到Future的真实值并重新渲染。

FutureBuilder(
   future: getValue(),
   initialData: "加载中...",
   builder:
       (BuildContext context, AsyncSnapshot<String> snapshot) {
       if (snapshot.hasData) {
         return Text(
           "${snapshot.data}",
           style: TextStyle(fontSize: 30, fontWeight: FontWeight.bold),
         );
       } else {
         return Text("${snapshot.error}");
       }
   }),

二、StreamBuilder

StreamBuilder组件与FutureBuilder组件相同之外的不同之处在于它是一个可以自动跟踪Stream的状态,并在Stream有变化时自动重绘的组件。
那么问题来了,什么是Stream?在这里,我们称之为数据流或事件流。Data Stream、Event Stream。
顾名思义,既然称之为“流”,那可以想象出这是一种不间断的操作。
我们可以通过使用Stream.periodic构造函数,并借助其count参数(当前Stream已被调用的次数,从0开始递增),制作一个一秒加一的计数器数据流。
方法:

Stream<int> counter() {
    return Stream.periodic(
      const Duration(seconds: 1),
      (count) => count
    );
  }

在组件中使用:

StreamBuilder(
    stream: counter(),
    builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
      switch(snapshot.connectionState) {
        case ConnectionState.none:
          return Text("无数据流");
        case ConnectionState.done:
          return Text("数据流关闭");
        case ConnectionState.waiting:
          return Text("等待数据");
        case ConnectionState.active:
          if(snapshot.hasData) {
            return Text("${snapshot.data}");
          }else {
            return Text("${snapshot.error}");
          }
        default:
          throw "connect error";
      }
    })

Flutter 异步操作
这种用法有点像js中的 setInterval() 一样。
StreamBuilder组件与FutureBuilder组件用法类似,只是在这里所传的参数不是future,而是stream,同时可以通过builder回传函数 获取Stream的4中状态,编写业务逻辑。用法与FutureBuilder组件中的状态类似,这里不过多重复。

上面这种普通数据流的写法只监听count()方法,如果需要支持多个监听者同时监听,则可以通过控制器的StreamController.broadcast构造函数创建一个广播数据流。实现界面多处位置监听并重绘StreamBuilder组件。

例如:

final _stream = StreamController<int>();

StreamBuilder(
    stream: _stream.stream.map((event) => "value:${event}"),
    builder: (context, snapshot) {
      if(snapshot.connectionState == ConnectionState.done) {
        return Text("close stream");
      }
      if(snapshot.hasData) return Text("${snapshot.data}");
      if(snapshot.hasError) return Text("${snapshot.error}");
      return CircularProgressIndicator();
  }),
  Row(
    children: [
      ElevatedButton(onPressed: () => _stream.add(666), child: Text("添加666")),
    	SizedBox(width: 20,),
     ElevatedButton(onPressed: () => _stream.add(888), child: Text("添加888")),
     SizedBox(width: 20,),
     ElevatedButton(onPressed: () => _stream.close(), child: Text("关闭数据流")),
    ],
  )

Flutter 异步操作
在最开始,Stream没有开始释放任何事件,这时StreamBuilder会先渲染一个加载组件,当点击第一个按钮,界面将会显示 value:666 字样。只要不关闭数据流,StreamBuilder就会一直监听,任何一处controller的变化。文章来源地址https://www.toymoban.com/news/detail-459623.html

到了这里,关于Flutter 异步操作的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Flutter Dart语言(05)异步

    该系列教程主要是为有一定语言基础 C/C++的程序员,快速学习一门新语言所采用的方法,属于在C/C++基础上扩展新语言的模式。 在Dart语言中,虽然没有像其他语言(如Java、C++、Python)中的传统多线程概念,但它采用了异步(asynchronous)编程模型来处理并发任务。Dart使用asy

    2024年02月14日
    浏览(41)
  • Flutter 的线程模型和异步原理

    本文字数:: 36130 字 预计阅读时间: 91 分钟 在 Android 应用中, 用户时常会遇到界面卡顿的情况,非常影响用户的体验。作为 Android 开发肯定都知道:应用在主线程里做了大量的耗时操作(例如文件读写, 数据库读写,网络访问,图片编解码等),就会导致 UI 不能及时刷新,

    2024年02月15日
    浏览(39)
  • 【flutter和android原生的异步】

    java android 中,是多线程的 1.flutter中不要以为异步就是多线程  2.flutter的线程隔离理论? UI 线程 : 在 Flutter 中,UI 线程负责处理用户界面的构建和渲染。所有与用户界面相关的操作,例如布局计算、绘制和处理用户输入等,都在 UI 线程中执行。 UI 线程是单线程的,也称为主

    2024年04月15日
    浏览(48)
  • Flutter 中的 Stream:异步编程的利器

    在Flutter中,异步编程是非常重要的一部分,特别是在处理用户输入、网络请求或其他涉及时间的操作时。Flutter提供了一种强大的工具,称为Stream,用于简化异步编程的过程。 Stream是一种用于处理异步数据的流式 API。它可以用于处理一系列事件,例如用户输入、网络请求的响

    2024年02月03日
    浏览(54)
  • Flutter实现CombineExecutor进行多个异步分组监听,监听第一个异步执行的开始和最后一个异步执行结束时机。

    1.场景 我们在调用接口时,很多时候会同时调用多个接口,接口都是异步执行,我们很难知道调用的多个接口哪个会最后执行完成,我们有时候需要对最后一个接口执行完成的时机监听,所以基于该需求,设计了CombineExecutor,对类似的需求进行监听。 2.代码 group_key.dart execu

    2024年02月09日
    浏览(32)
  • vue前端开发自学,父子组件传递数据,借助于Props实现子传父

    vue前端开发自学,父子组件传递数据,借助于Props实现子传父! 之前我们说过,Props这个是用在父传子的情况下,今天为大家介绍的代码,就是在父组件里,自定义事件,绑定一个函数,让子组件可以接受到这个自定义事件绑定的函数,从而“委婉”的传递数据给父组件。 如图

    2024年01月23日
    浏览(42)
  • Vue.js 中的异步组件是什么?如何使用异步组件?

    在 Vue.js 中,异步组件是一种延迟加载组件的方式,可以大大提高应用程序的性能和加载速度。本文将介绍 Vue.js 中异步组件的概念、优势以及如何使用异步组件。 在传统的 Vue.js 开发中,组件是在应用程序启动时就立即加载的。这种方式虽然简单,但是会导致应用程序的初始

    2024年02月12日
    浏览(38)
  • Flutter实现ControlExecutor进行多个异步任务执行时监听状态并可指定最后执行的异步并在指定的异步执行完毕后结束executor并回调。

    1.场景 当有多个接口请求时,且接口调用不是同时进行时,而且接口调用有可能时链式的,中间也有可能加入别的逻辑,但是需要在第一个接口调用时打开等待框,在最后一个接口调用完成时关闭等待框类似需求时,可以用到ControlExecutor进行接口执行过程的监听,并可标记最

    2024年02月09日
    浏览(38)
  • VUE组件--动态组件、组件保持存活、异步组件

    有些场景可能会需要在多个组件之间进行来回切换,在vue中则使用 component :is=\\\"...\\\" 来实现组件间的来回切换  changeHandler()使用三目运算符,来实现Component1和Component2之间的相互切换  默认为组件1   当组件1切换到组件2时,组件1会被强行销毁 初始态:  点击“更新数据”: 点

    2024年01月19日
    浏览(37)
  • 【Vue】动态组件和异步组件

    ‍‍今天我们来学习动态组件和异步组件。 什么是动态组件? 什么是异步组件? 代码示例: 解读代码: 子组件我给它起个名字叫做input-item,‍‍我创建这样的一个组件,然后它里面会有一个input框, 在这里面我可以用一下组件,怎么用? 我们直接在模板里面去写一下 i

    2024年02月08日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包