热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

android开发分享Flutter假异步的实现示例

就像android有handle一样,消息队列这东西好像还真是系统必备,flutter也有自己的消息队列,只不过队列直接封装在了dart的线程类型

就像 android 有 handle 一样,消息队列这东西好像还真是系统必备,flutter 也有自己的消息队列,只不过队列直接封装在了 dart 的线程类型 isolate 里面了,不过 flutter 还是提供了 futrue 这个 api 来专门来操作各种消息,以及实现基于消息队列的假异步

flutter 的“异步”机制

这里的异步是加了引号的,可见此异步非真异步,而是假异步。flutter 的 异步 不是开新线程,而是往所属线程的 消息队列 中添加任务,当然大家也可以按上文那样自己展开真异步操作

flutter 对代码分2类: 同步代码和异步代码

  • 同步代码:传统一行行写下来,一行行执行的代码
  • 异步代码:通过 future api 把任务添加到 isolate 所属消息队列执行的伪异步
  • 执行顺序:先运行同步代码,再运行异步代码

为啥,很明显啊,异步代码是往消息队列里添加任务,那肯定得等现在的代码运行完了,线程有空闲了才能开始执行消息队列里的任务呀~

举个例子:

  void test() {    print("aa");    future(() => print("futrue"));    print("bb");  }  ~~~~~~~~~~~log~~~~~~~~~~~~~  i/flutter (10064): aa  i/flutter (10064): bb  i/flutter (10064): futrue

print("futrue")) 任务等到最后才执行的…

flutter 提供了往 消息队列 添加数据的 api: future

往 microtask 队列添加任务

  schedulemicrotask((){   // ...code goes here...  });     new future.microtask((){    // ...code goes here...  });

往 event 队列添加任务

  new future(() {   // ...code goes here...  });

future 的基本使用

future 对象是 flutter 专门提供的,基于消息队列实现异步的类,future 对象会把自身当做一个任务添加到消息队列中去排队执行

future 对象接受的是一个函数,就是要执行的任务,用 () => ... 简写也是可以的

  void task() {    print("aa");  }    var futrue = future(task);

创建 future 任务方式:

  • future()
  • future.microtask()
  • future.sync() – 同步任务
  • future.value()
  • future.delayed() – 延迟xx时间添加任务
  • future.error() – 错误处理

我们来看几个代表性的:

future.sync() – 阻塞任务,会阻塞当前代码,sync 的任务执行完了,代码才能走到下一行

  void test() {    print("aa");    future.sync(() => print("futrue"));    print("bb");  }  ~~~~~~~~~~~~log~~~~~~~~~~~~~~  i/flutter (10573): aa  i/flutter (10573): futrue  i/flutter (10573): bb

future.delayed() – 延迟任务,指定xx时间后把任务添加到消息队列,要是消息队列前面有人执行的时间太长了,那么执行时间点就不能把握了,这点大家要知道

  void test() {    print("aa");    future.delayed(duration(milliseconds: 500),() => print("futrue"));    print("bb");  }  ~~~~~~~~~~~~log~~~~~~~~~~~~~~  i/flutter (10573): aa  i/flutter (10573): bb  i/flutter (10573): futrue

future 的链式调用

future 也支持链式调用的,在 api 使用上也是很灵活的,提供了下面的选择给大家

.then – 在 future 执行完后执行,相当于一个 callback,而不是重新创建了一个 future

   future.delayed(duration(seconds: 1),(){     print(("aaa"));     return "aa";    }).then((value){     print(value);    });

.catcherror – future 不管在任何位置发生了错误,都会立即执行 catcherror

    future.delayed(duration(seconds: 1),(){     throw exception("aaa");    }).then((value){     print(value);    }).catcherror((error){     print(error);    });

.whencomplete – 不管是否发生异常,在执行完成后,都会执行该方法

   future.delayed(duration(seconds: 1), () {     throw exception("aaa");    }).then((value) {     print(value);    }).catcherror((error) {     print(error);    }).whencomplete(() {     print("complete...");    });

.wait – 可以等待所有的 future 都执行完毕再走 then 的方法

  future.wait([     // 2秒后返回结果     future.delayed(new duration(seconds: 2), () {      return "hello";     }),     // 4秒后返回结果     future.delayed(new duration(seconds: 4), () {      return " world";     })    ]).then((results) {     print(results[0] + results[1]);    }).catcherror((e) {     print(e);    });

大家想想啊

  futrue()    .then()    .then()    ...

这样的链式写法不就是标准的去 callback 回调地狱的方式嘛

async/await 关键字

async/await 这组关键字是系统提供的另一种实现 异步 任务的 api, async/await 底层还是用 futrue 实现的,从使用上看是对 futrue 的简化,本质上还是基于 消息队列 实现的异步,是 假异步 ,和 isoalte 是不一样的

async/await 的特点就是: 成对出现

  • async – 修饰方法,用 async 声明的方法都是耗时的
  • await – 调用 async 方法时使用,也可以在 async 方法内部是适用,await 表示阻塞,下面的任务必须等 await 调用的方法执行完之后才能执行

比如这样:

   anysnctest() async {    print("async 休眠 start...");    sleep(duration(seconds: 1));    print("async 休眠 end...");   }    await anysnctest();

本质上 await 调用的方法其实是把这个方法包装到 futrue 中去消息队列里执行,只不过是: future.sync() 阻塞式的 future 任务

async 在布局中也是可以直接用的

  class testwidgetstate extends state {   int _count = 0;      @override   widget build(buildcontext context) {    return material(      flatbutton(        onpressed: () async {          _count = counteven(1000000000);          setstate(() {});        },        child: text(          _count.tostring(),        )),    );   }

async/await 是阻塞式的函数

实验1:

   // 这是异步任务代码   aaa() async{    print("main1...");    await anysnctest();    print("main2...");    print("main3...");   }     anysnctest() async {    print("async 休眠 start...");    sleep(duration(seconds: 1));    print("async 休眠 end...");   }      // 点击按钮去执行    widget build(buildcontext context) {    return raisedbutton(     child: (text("click!")),     onpressed: () async {      await aaa();     },    );   }

Flutter 假异步的实现示例 

可以看到 async/await

执行的方法的确是阻塞时的,至少在这个 async 方法里绝对是阻塞式的

实验2:

那么范围扩展一下,在 async 外面再来看看 async/await 是不是阻塞式的? 有人说 async/await 和协程一样 ,协程的关键点在于非竞争式资源,协程的概念中,当多个协程中有一个协程挂起之后,并不会阻塞 cpu,cpu 回去执行其他协程方法,直到有空闲了再来执行之前挂起后恢复的协程,虽然在协程看来我挂起了线程,但其实 cpu 不会被协程挂起阻塞,这点就是协程的核心优势,大大提升多线程下的执行效率。

从这点出发我们就能知道 async/await 是不是又一个协程了,看看他阻塞 cpu,我们在 await 之后看看 async 后面的代码会不会执行就 ok了

   // 还是这组方法   aaa() async{    print("main1...");    await anysnctest();    print("main2...");    print("main3...");   }     anysnctest() async {    print("async 休眠 start...");    sleep(duration(seconds: 1));    print("async 休眠 end...");   }      // 执行,注意此时按钮的点击方法不是 async 的   widget build(buildcontext context) {    return raisedbutton(     child: (text("click!")),     onpressed: () {      print("click1...");      aaa();      print("click2...");      print("click3...");     },    );   }

  i/flutter ( 5733): click1...  i/flutter ( 5733): main1...  i/flutter ( 5733): async 休眠 start...  i/flutter ( 5733): async 休眠 end...  i/flutter ( 5733): click2...  i/flutter ( 5733): click3...  i/flutter ( 5733): main2...  i/flutter ( 5733): main3...

await 阻塞是真的阻塞 cpu 了,所以 async/await 不是协程,但是大家注意啊,在 await 结速阻塞之后执行的是 click2 也就是 async 外部的方法,说明 await 标记的方法返回的都是 futrue 对象的说法是正确的,队列只有在线程空闲时才会执行,显然此时线程不是空闲的,点击方法还没执行完呢

实验3:

这次做对比实验,把点击事件也变成 async 的看看执行顺序

   // 还是这组方法   aaa() async{    print("main1...");    await anysnctest();    print("main2...");    print("main3...");   }     anysnctest() async {    print("async 休眠 start...");    sleep(duration(seconds: 1));    print("async 休眠 end...");   }      // 执行    widget build(buildcontext context) {    return raisedbutton(     child: (text("click!")),     onpressed: () async {      print("click1...");      await aaa();      print("click2...");      print("click3...");     },    );   }

  i/flutter ( 5733): click1...  i/flutter ( 5733): main1...  i/flutter ( 5733): async 休眠 start...  i/flutter ( 5733): async 休眠 end...  i/flutter ( 5733): main2...  i/flutter ( 5733): main3...  i/flutter ( 5733): click2...  i/flutter ( 5733): click3...

这样看的话在 async 方法内部,是严格按照顺序执行的

async 方法的格式

1. async 标记的方法返回值都是 futrue 类型的

上文书哦说 await 调用的方法返回的都是 futrue 对象,那么就是说在声明 async 函数时,返回值都是 futrue 类型的,futrue 内部包裹实际的返回值类型

  futrue getdata() async {   data = await http.get(uri.encodefull(url), headers: {"accept": "application/json"});    }

futrue 我们可以不写,dart 也会自动推断出来,但是我们一定要知道是 futrue 类型的,要不有时会报类型错误

我们在用的时候都是配合 await 使用的,这时候可以直接用具体类型值接返回值了

  string data = await getdata();

记住:

future就是event,很多flutter内置的组件比如前几篇用到的http(http请求控件)的get函数、refreshindicator(下拉手势刷新控件)的onrefresh函数都是event。每一个被await标记的句柄也是一个event,每创建一个future就会把这个future扔进event queue中排队等候安检~

stream

streamfuture 一样都是假异步操作,区别是 stream 可以接受多次数据,我不详细展开了,有待以后详细研究

  stream.fromfutures([   // 1秒后返回结果   future.delayed(new duration(seconds: 1), () {    return "hello 1";   }),   // 抛出一个异常   future.delayed(new duration(seconds: 2),(){    throw assertionerror("error");   }),   // 3秒后返回结果   future.delayed(new duration(seconds: 3), () {    return "hello 3";   })  ]).listen((data){    print(data);  }, onerror: (e){    print(e.message);  },ondone: (){    });

以上就是android开发分享Flutter 假异步的实现示例的全部内容,希望对大家的学习有所帮助,也希望大家多多支持<编程笔记>。


推荐阅读
  • 时域|波形_语音处理基于matlab GUI音频数据处理含Matlab源码 1734期
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了语音处理基于matlabGUI音频数据处理含Matlab源码1734期相关的知识,希望对你有一定的参考价值。 ... [详细]
  • Flutter 布局(四) Baseline、FractionallySizedBox、IntrinsicHeight、IntrinsicWidth详解
    本文主要介绍Flutter布局中的Baseline、FractionallySizedBox、IntrinsicHeight、IntrinsicWidth四种控件,详细介绍了其布局 ... [详细]
  • 6(自)、交换机之关键字模式
    上一节中的我们的日志系统将所有消息广播给所有消费者,对此我们想做一些改变,例如我们希望将日志消息写入磁盘的程序仅接收严重错误(error),而不存储那些警告(warnning)或者 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • 本文介绍了操作系统的定义和功能,包括操作系统的本质、用户界面以及系统调用的分类。同时还介绍了进程和线程的区别,包括进程和线程的定义和作用。 ... [详细]
  • MySQL数据库锁机制及其应用(数据库锁的概念)
    本文介绍了MySQL数据库锁机制及其应用。数据库锁是计算机协调多个进程或线程并发访问某一资源的机制,在数据库中,数据是一种供许多用户共享的资源,如何保证数据并发访问的一致性和有效性是数据库必须解决的问题。MySQL的锁机制相对简单,不同的存储引擎支持不同的锁机制,主要包括表级锁、行级锁和页面锁。本文详细介绍了MySQL表级锁的锁模式和特点,以及行级锁和页面锁的特点和应用场景。同时还讨论了锁冲突对数据库并发访问性能的影响。 ... [详细]
  • 第一步:PyQt4Designer设计程序界面该部分设计类同VisvalStudio内的设计,改下各部件的objectName!设计 ... [详细]
  • 由于同源策略的限制,满足同源的脚本才可以获取资源。虽然这样有助于保障网络安全,但另一方面也限制了资源的使用。那么如何实现跨域呢,以下是实现跨域的一些方法。 ... [详细]
  • RabbitMq之发布确认高级部分1.为什么会需要发布确认高级部分?在生产环境中由于一些不明原因,导致rabbitmq重启,在RabbitMQ重启期间生产者消息投递失败,导致消息丢 ... [详细]
  • 开发笔记:图像识别基于主成分分析算法实现人脸二维码识别
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了图像识别基于主成分分析算法实现人脸二维码识别相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 使用Flutternewintegration_test进行示例集成测试?回答首先在dev下的p ... [详细]
  • 当我在doWork方法中运行代码时,通过单击button1,进度条按预期工作.但是,当我从其他方法(即btn2,btn3)将列表传递给doWork方法时,进度条在启动后会跳转到10 ... [详细]
  • java多线程获取线程返回结果
    我们在使用java多线程编写相关业务代码时,往往有这样一种情况,某个线程依赖于其他线程执行结果。也就是说,我们需要在一个线程中获取另一个线程的信息。可以分为两种情况,一种是轮询,一 ... [详细]
  • Flutter第六章(BottomNavigationBar ,AppBar,TabBar ,TabController 以及案例)
    版权声明:本文为作者原创书籍。转载请注明作者和出处,未经授权,严禁私自转载,侵权必究!!!情感语录:如果你想得到从未拥有过的东西,那么你必须去做从未做过的事 ... [详细]
author-avatar
web+php
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有