【Flutter】Dart:异步

news2024/10/23 23:31:09

在现代应用开发中,异步编程是不可或缺的部分,尤其是在开发用户界面、网络请求、文件操作等涉及长时间执行的操作时,异步能避免阻塞主线程,从而提升应用的响应速度和用户体验。在 Dart 中,异步编程主要依靠 FutureStream,此外,Dart 还支持 生成器函数 来简化某些异步操作的实现。

本教程将深入介绍 Dart 中的异步编程,涵盖 FutureStream 以及生成器函数的使用。

异步编程概述

在 Dart 中,异步编程的主要目标是避免阻塞主线程(UI 线程),让长时间运行的任务在后台执行,同时主线程可以继续响应用户操作。异步编程通过 FutureStream 来实现。

  • Future:表示一个可能在将来某个时间完成的异步操作,可以成功返回一个结果或抛出错误。
  • Stream:类似于 Future,但可以在一段时间内多次返回数据。
  • 生成器函数:一种简化异步数据生成的机制,通常与 async*yield 关键字结合使用。

Future详解

Future 是 Dart 异步编程的基础,它表示一个将在未来完成的计算。Future 有两种状态:未完成(pending)完成(completed)。当一个异步操作完成时,Future 要么返回结果(成功),要么抛出异常(失败)。

创建 Future

Future 可以通过多种方式创建,包括 Future.value()Future.error() 和异步函数 async 的返回值。

示例:使用 Future.value()

void main() {
  Future<String> future = Future.value('Hello, Dart Future!');
  future.then((value) => print(value));
}

示例:使用异步函数

Future<String> fetchData() async {
  // 模拟网络请求,延迟 2 秒返回结果
  await Future.delayed(Duration(seconds: 2));
  return 'Data fetched!';
}

void main() async {
  print('Fetching data...');
  String data = await fetchData();
  print(data);
}

在上面的示例中,fetchData 是一个异步函数,返回一个 Future<String>,并通过 await 关键字等待 Future 完成。在调用该函数时,主线程不会被阻塞。

thencatchError 处理结果

使用 Future 时,结果通常通过 then() 方法处理,错误通过 catchError() 处理。then() 方法会在 Future 完成后执行回调。

示例:处理结果和错误

void main() {
  Future<int> future = Future(() {
    return 42;
  });

  future.then((value) {
    print('Future completed with value: $value');
  }).catchError((error) {
    print('An error occurred: $error');
  });
}

asyncawait

在 Dart 中,asyncawait 提供了一种简洁的语法来处理异步操作,使代码看起来更像同步代码。

示例:使用 asyncawait

Future<int> fetchNumber() async {
  await Future.delayed(Duration(seconds: 1));  // 模拟耗时操作
  return 100;
}

void main() async {
  print('Start fetching number...');
  int number = await fetchNumber();
  print('Fetched number: $number');
}

通过 async 标记一个函数为异步,使用 await 等待 Future 完成。在上面的例子中,fetchNumber() 返回一个 Future<int>,主线程等待该 Future 完成后继续执行。

Stream详解

Future 不同,Stream 代表一个异步数据的序列,可以多次发出数据。在 Dart 中,Stream 是处理大量异步事件(如用户输入、文件操作、网络请求)的重要工具。

创建 Stream

Stream 主要有两种类型:单订阅流(single-subscription stream)广播流(broadcast stream)

  • 单订阅流:只能有一个监听器。
  • 广播流:可以有多个监听器,通常用于事件广播。

示例:单订阅流

void main() {
  Stream<int> stream = Stream.fromIterable([1, 2, 3, 4, 5]);

  stream.listen((value) {
    print('Stream value: $value');
  });
}

示例:广播流

void main() {
  Stream<int> stream = Stream<int>.periodic(Duration(seconds: 1), (count) => count).asBroadcastStream();

  stream.listen((value) {
    print('Listener 1: $value');
  });

  stream.listen((value) {
    print('Listener 2: $value');
  });
}

在广播流中,多个监听器可以同时监听同一个 Stream,在上面的例子中,两个监听器同时监听并处理同一个 Stream

监听 Stream

通过 listen() 方法可以订阅 Stream,并处理流中的数据。

示例:处理 Stream

Stream<int> countStream(int max) async* {
  for (int i = 1; i <= max; i++) {
    yield i;
    await Future.delayed(Duration(seconds: 1));  // 模拟延迟
  }
}

void main() async {
  Stream<int> stream = countStream(5);

  await for (int value in stream) {
    print('Stream value: $value');
  }
}

在这个例子中,countStream() 是一个生成器函数,通过 yield 发出数据,并通过 await for 逐个读取 Stream 中的数据。

转换 Stream

Stream 提供了许多方法用于转换流中的数据,比如 map()where()reduce() 等。

示例:转换 Stream

void main() {
  Stream<int> stream = Stream.fromIterable([1, 2, 3, 4, 5]);

  stream
    .map((value) => value * 2)
    .where((value) => value > 5)
    .listen((value) {
      print('Transformed Stream value: $value');
    });
}

这个例子展示了如何使用 map()where() 对流中的数据进行转换和过滤。

生成器函数

生成器函数可以生成一系列异步数据,它们使用 async*yield 关键字。生成器函数返回一个 Stream,可以逐步生成多个数据项。

sync*async*

  • sync*:同步生成器,用于生成一系列同步数据。
  • async*:异步生成器,用于生成一系列异步数据。

示例:使用 sync*

Iterable<int> syncGenerator(int max) sync* {
  for (int i = 1; i <= max; i++) {
    yield i;
  }
}

void main() {
  var generator = syncGenerator(5);

  for (var value in generator) {
    print('Generated value: $value');
  }
}

示例:使用 async*

Stream<int> asyncGenerator(int max) async* {
  for (int i = 1; i <= max; i++) {
    yield i;
    await Future.delayed(Duration(seconds: 1));
  }
}

void main() async {
  await for (var value in asyncGenerator(5)) {
    print('Generated async value: $value');
  }
}

async* 生成器与 sync* 不同的是,它会返回 Stream,并且可以处理异步任务。上面的例子中,asyncGenerator() 生成异步数据,并通过 await for 逐步读取。

总结

Dart 中的异步编程通过 FutureStream 和生成器函数为开发者提供了强大的工具,帮助处理复杂的异步操作。Future 用于处理一次性的异步任务,Stream 适合处理一系列异步事件,而生成器函数则提供了简洁的异步数据生成机制。

通过合理使用异步编程模式,开发者可以编写出高效、响应迅速的 Flutter 应用。在实际开发中,掌握这些异步工具对于提升应用性能和用户体验至关重要。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2221956.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vscode + EIDE +CortexDebug 调试Stm32(记录)

{// 使用 IntelliSense 了解相关属性。 // 悬停以查看现有属性的描述。// 欲了解更多信息&#xff0c;请访问: https://go.microsoft.com/fwlink/?linkid830387"version": "0.2.0","configurations": [{"cwd": "${workspaceRoot…

w~自动驾驶合集9

我自己的原文哦~ https://blog.51cto.com/whaosoft/12320882 #自动驾驶数据集全面调研 自动驾驶技术在硬件和深度学习方法的最新进展中迅速发展&#xff0c;并展现出令人期待的性能。高质量的数据集对于开发可靠的自动驾驶算法至关重要。先前的数据集调研试图回顾这些数据集&…

Djang学习- URL反转

代码中url书写规范&#xff1a; 、 url反向解析 urls: path(test/url, views.test_url),path(test_result/<int:age>, views.test_result, name"rl") views: def test_url(request):return render(request, test_url.html)def test_result(request,age):re…

Vue3学习:vite项目中图片不能显示,报错 require is not defined

今天做了一个案例“给你喜欢的人送花”&#xff0c;如果喜欢谁&#xff0c;就给谁送花&#xff0c;最多可以送5朵。运行效果如下。 这个项目是使用 npm create vitelatest 命令创建的。 包括2个组件&#xff1a; 根组件App.vue子组件HelloVote.vue。 目录结构如图所示&#x…

资讯 | 财富通科技政务协同办公管理软件通过麒麟软件适配认证

2024年9月25日&#xff0c;财富通科技研发的政务协同办公管理软件成功通过中国国产操作系统麒麟软件的适配认证。本次认证是继公司区块链产品“基于区块链的企业及人员资质数字证书服务平台”认证以后得第二次认证。这一成就标志着财富通科技在推动国产软件生态建设方面迈出了坚…

基于SSM+微信小程序的家庭记账本管理系统(家庭1)

&#x1f449;文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1、项目介绍 1、管理员端功能有首页、个人中心、用户管理&#xff0c;消费详情管理、收入详情管理、系统管理等。 2、用户端功能有首页、消费详情、收入详情、论坛信息、我的等功能。 2、项目技术 …

数据结构作业day2

作业一&#xff1a;结构体数组存储学生信息&#xff08;姓名&#xff0c;年龄&#xff0c;分数&#xff09;&#xff0c;完成输入学生信息&#xff0c;输出学生信息&#xff0c;求学生成绩之和&#xff0c;求最低学生成绩。 main.c #include "test.h"int main(int …

GitLab 老旧版本如何升级?

极狐GitLab 正式对外推出 GitLab 专业升级服务 https://dl.gitlab.cn/cm33bsfv&#xff01; 专业的技术人员为您的 GitLab 老旧版本实例进行专业升级&#xff01;服务详情可以在官网查看详细解读&#xff01; 那些因为老旧版本而被攻击的例子 话不多说&#xff0c;直接上图&a…

视频转GIF,5个简单好用的转换工具任你选!

GIF&#xff08;Graphics Interchange Format&#xff09;&#xff0c;作为一种轻量级的图像文件格式&#xff0c;因其能够存储多帧图像形成简单动画而广受欢迎。无论是动画影视片段&#xff0c;还是日常生活的小确幸&#xff0c;GIF都能将其定格为生动的视觉语言。当我们想要将…

FileLink跨网文件摆渡系统:重构跨网文件传输新时代

在数字化浪潮的推动下&#xff0c;企业对于数据的高效利用和安全管理提出了前所未有的要求。面对不同网络环境间的文件传输难题&#xff0c;传统方法往往显得力不从心&#xff0c;不仅效率低下&#xff0c;还存在极大的安全隐患。而FileLink跨网文件摆渡系统的出现&#xff0c;…

深信服超融合HCI6.8.0R2滚动热升级至HCI6.9.1

PS&#xff1a;滚动热升级没有业务影响&#xff0c;集群内主机逐台升级&#xff0c;会自动迁移运行中的虚拟机至其他主机&#xff1b; 整体巡检加上升级完成大概要三个小时的时间。如果在升级过程中&#xff0c;有跨集群迁移的任务&#xff0c;需要先停掉&#xff0c;不然无法…

excel将文本型数字转变为数值型数字

问题导入&#xff1a;复制数字到excel表格中&#xff0c;但是表格中数字显示为文本&#xff0c;且无法通过常规方法转变为可进行四则运算的数字。例如&#xff1a;在i3单元格中输入常规的转换方法仍然报错。在j3单元格中输入ISTEXT(H3)显示h3单元格确实为文本。 解决办法&#…

记录:网鼎杯2024赛前热身WEB01

目录扫描&#xff0c;发现上传点&#xff0c;判断可能存在文件上传漏洞&#xff0c;并根据文件后缀判断网站开发语言为php 编写蚁剑一句话木马直接上传 蚁剑连接 这里生成 的flag是随机的&#xff0c;因为烽火台反作弊会随机生成环境&#xff0c;在一顿查找后&#xff0c;在hom…

自动驾驶系列—激光雷达点云数据在自动驾驶场景中的深度应用

&#x1f31f;&#x1f31f; 欢迎来到我的技术小筑&#xff0c;一个专为技术探索者打造的交流空间。在这里&#xff0c;我们不仅分享代码的智慧&#xff0c;还探讨技术的深度与广度。无论您是资深开发者还是技术新手&#xff0c;这里都有一片属于您的天空。让我们在知识的海洋中…

Leetcode 柱状图中最大的矩形

h 是右边界&#xff0c;连续多个高度递增的柱子&#xff0c;如果遇到下一个 h < 栈顶元素(是最大的元素&#xff0c;单调递增栈)&#xff0c;那么会不断出栈来更新计算最大面积。 并非是一次性计算出最大面积的&#xff0c;很重要的一点是while (!stack.isEmpty()这一部分的…

使用Docker启动的Redis容器使用的配置文件路径等问题以及Python使用clickhouse_driver操作clickhouse数据库

一、使用Docker启动的Redis容器使用的配置文件路径等问题 1.docker启动的redis使用的配置文件路径是什么 使用docker搭建redis服务&#xff0c;本身redis启动的时候可以指定配置文件的&#xff0c; redis-server /指定配置文件路径/redis.conf。 但手上也没有一个redis配置文件…

SpringCloud无介绍快使用,sentinel服务熔断功能与持久化(二十四)

TOC 问题背景 从零开始学springcloud微服务项目 注意事项&#xff1a; 约定 > 配置 > 编码IDEA版本2021.1这个项目&#xff0c;我分了很多篇章&#xff0c;每篇文章一个操作步骤&#xff0c;目的是显得更简单明了controller调service&#xff0c;service调dao默认安装ngi…

JavaEE进阶----18.<Mybatis补充($和#的区别+数据库连接池)>

详解了 1.$和#的区别 2.数据库连接池。 3.简单了解MySQL企业开发规范 一、Mybatis面试题&#xff1a;$和#的区别是什么&#xff1f; MyBatis 参数赋值有两种方式&#xff0c;咱们前面使用了 #{} 进行赋值&#xff0c;接下来我们看下二者的区别。 1.1 #是预编译SQL&#xff0c;$…

序列化问题记录:Jackson 与 Fastjson 的注解

前言 Java 后端开发中&#xff0c;我们经常需要处理 JSON 序列化和反序列化的问题。Spring 框架默认使用 Jackson 作为 JSON 处理库&#xff0c;但在某些情况下&#xff0c;我们也可能会使用 Fastjson 来处理特定的序列化需求。由于这两种库的注解不完全兼容&#xff0c;因此在…

springboot扩展点都有哪些?

在Spring Boot中&#xff0c;扩展点指的是能够自定义或增强Spring Boot功能的机制。这些扩展点允许开发者在Spring Boot的基础设施之上做定制化配置、行为修改或增强。Spring Boot主要有以下几类扩展点&#xff1a; 1. ApplicationRunner 和 CommandLineRunner 这两个接口允许…