服务粉丝

我们一直在努力
当前位置:首页 > 财经 >

Flutter中的异步执行策略

日期: 来源:群英传收集编辑:徐宜生

点击上方蓝字关注我,知识会给你力量


在Flutter中,如何执行一段延迟执行的异步代码?我们可以找到下面这些方法。

  • scheduleMicrotask
  • Future.microtask
  • Future
  • Future.delayed
  • Timer.run
  • WidgetsBinding.addPostFrameCallback
  • SchedulerBinding.addPostFrameCallback

你可能会说,这是相当多的选择,但是它们彼此之间有些什么异同呢?

Event Loop and Multithreading

Dart是一个单线程模型。但是你的Flutter应用同样可以同时做多件事情,这就是「Event Loop」发挥作用的地方。Event Loop是一个无尽的循环,它执行预定的events。这些events(或者只是代码块)必须是轻量级的,否则,你的应用程序会感觉卡顿。

每个event,如按下按钮或网络请求,都被安排在一个事件队列中,等待被事件循环捡起并执行。这种设计模式在UI和其他处理任何类型事件的系统中相当常见。

在Dart的单线程模型中,还有一个Microtask。它组成了Event Loop中的另一一个队列,即Microtask Queue。关于这个队列你唯一需要记住的是,在事件本身被执行之前,所有安排在Microtask Queue的任务都将在Event Loop循环的一次迭代中被执行。可以通过这个链接查看更多内容:https://dart.cn/articles/archive/event-loop

Events

任何进入event queue的东西都被称之为Event。这是Flutter中调度异步任务的默认方法。为了调度一个Event,我们把它添加到event queue中,由Event Loop来接收。这种方法被许多Flutter机制所使用,如I/O、手势事件、Timer等。

Timer

Timer是Flutter中异步任务的基础。它被用来安排event queue中的代码执行,无论是否有延迟执行的需要。由此产生的有趣的事实是,如果当前队列很忙,你的定时器将永远不会被执行,即使时间到了。

Timer.run(() {
    print("Timer");
});


Futureand Future.delayed

Future是Dart中使用的非常广泛的一个异步方法,它的内部实现,实际上也就是基于Timer的。

Future<void>(() {
    print("Future Event");
});

Future<void>.delayed(Duration.zero, () {
    print("Future.delayed Event");
});

它的内部实现如下。

Microtasks

如前所述,所有调度的microtasks都会在下一个调度的Event之前执行。建议避免使用这个队列,除非绝对需要异步执行代码,而且要在event queue的下一个事件之前处理。你也可以把这个队列看成是属于前一个事件的任务队列,因为它们将在下一个事件之前完成。如果这个队列不断膨胀,就会完全冻结你的应用程序,因为它必须先执行这个队列中的所有内容,然后才能进行其事件队列的下一次迭代,例如处理用户输入,甚至渲染应用程序本身。

scheduleMicrotask

顾名思义,在microtask queue中调度一个块代码。与Timer类似,如果出错,会使应用程序崩溃。

scheduleMicrotask(() {
    print("Microtask");
});


Future.microtask

与我们之前看到的类似,但它将我们的microtask包裹在一个try-catch块中,以一种漂亮而干净的方式返回执行结果或异常。

Future<void>.microtask(() {
    print("Microtask");
});

它的内部实现如下。

Post Frame Callback

前面两种方法只涉及到lower-level Event Loop,而现在我们要转到Flutter领域。这个Callback会在渲染管道完成时被调用,所以它与widget的生命周期相管理。当它被调度时,它只会被调用一次,而不是在每一帧都回调。使用addPostFrameCallback方法,你可以安排一个或多个回调,在界面渲染完成后被调用。

所有预定的Callback将在frame结束时按照它们被添加的顺序执行。到这个回调被调用的时候,可以保证Widget的构建过程已经完成。通过一些方法,你甚至可以访问Widget(RenderBox)的布局信息,比如它的大小,并做其他的一些事情。Callback本身将在正常的event queue中运行,Flutter默认使用该队列来处理几乎所有事情。

SchedulerBinding

这是一个负责绘图回调的mixin类,实现了我们感兴趣的方法。

SchedulerBinding.instance.addPostFrameCallback((_) {
    print("SchedulerBinding");
});


WidgetsBinding

我特意包括这个,因为它经常和SchedulerBinding一起被提及。它从SchedulerBinding中继承了这个方法,并有与我们的主题无关的一些额外方法。一般来说,你使用SchedulerBinding或WidgetsBinding并不重要,两者将执行位于SchedulerBinding中的完全相同的代码。

WidgetsBinding.instance.addPostFrameCallback((_) {
    print("WidgetsBinding");
});


总结

由于我们今天学到了很多理论知识,我强烈建议大家多玩一会儿,以确保我们能正确地掌握它。我们可以在之前的initState中使用下面的代码,并尝试预测它将以何种顺序被执行,这并不是一件看起来很容易的事情。

SchedulerBinding.instance.addPostFrameCallback((_) {
  print("SchedulerBinding");
});

WidgetsBinding.instance.addPostFrameCallback((_) {
  print("WidgetsBinding");
});

Timer.run(() {
  print("Timer");
});

scheduleMicrotask(() {
  print("scheduleMicrotask");
});

Future<void>.microtask(() {
  print("Future Microtask");
});

Future<void>(() {
  print("Future");

  Future<void>.microtask(() {
    print("Microtask from Event");
  });
});

Future<void>.delayed(Duration.zero, () {
  print("Future.delayed");

  Future<void>.microtask(() {
    print("Microtask from Future.delayed");
  });
});

输出结果如下所示。

I/flutter (31989): scheduleMicrotask
I/flutter (31989): Future Microtask
I/flutter (31989): SchedulerBinding
I/flutter (31989): WidgetsBinding
I/flutter (31989): Timer
I/flutter (31989): Future
I/flutter (31989): Microtask from Event
I/flutter (31989): Future.delayed
I/flutter (31989): Microtask from Future.delayed

现在我们了解了这么多细节,你可以对如何安排你的代码做出深思熟虑的决定。作为一个经验法则,如果你需要你的上下文或与Layout或UI相关的东西,请使用addPostFrameCallback。在任何其他情况下,用Future或Future.delayed在标准的event queue中进行调度应该是足够的。microtask queue是非常小众的东西,你可能永远不会遇到,但它仍然值得了解。当然,如果你有一个繁重的任务,你就会考虑创建一个Isolate。

翻译自——https://oleksandrkirichenko.com/blog/delayed-code-execution-in-flutter/

向大家推荐下我的网站 https://www.yuque.com/xuyisheng  点击原文一键直达

专注 Android-Kotlin-Flutter 欢迎大家访问



往期推荐


本文原创公众号:群英传,授权转载请联系微信(Tomcat_xu),授权后,请在原创发表24小时后转载。
< END >
作者:徐宜生

更文不易,点个“三连”支持一下

相关阅读

  • FlutterComponent最佳实践之Widget尺寸

  • 点击上方蓝字关注我,知识会给你力量在Flutter和在Native中,对一个Widget的尺寸测量,一直都是一个非常麻烦的事情,大部分时间,我们都是按照约束和具体的尺寸来进行布局,但有些时候,
  • 【滋味】春天,尝尝这道用枸杞头制作的早餐

  • 枸杞头就是枸杞芽,即枸杞最上端的嫩叶。初春的枸杞头略带苦味,但很是爽口,后味微甜,加入普通的食材中,就能成就一道营养、精致的菜肴!今天,就给大家介绍一道简单又好吃的早餐——枸
  • 在线可玩的 ChatGPT

  • 这段时间发布了很多AI产品,包括GPT4,MidjourneyV5 ,文心一言,Microsoft 365 Copilot,ai产品要百花齐放了,这里就分享几个基于chatgpt的网站,在线可玩。ChatGPT prompts这个网站收集
  • 【该劝退了】国内音视频开发的前景怎么样?

  • 作者:cfwang链接:https://www.zhihu.com/question/464940771/answer/2939864399在知乎上看到的这个问题 国内音视频开发的前景怎么样 ?,除了这位 cfwang 老哥是在认真回答,其他全
  • 今年面试好激烈!

  • 金三银四过去一半,市场火热,但是大家就业压力却没有缓解多少。很多粉丝后台留言,Java程序员面临的竞争太激烈了……我自己也有实感,多年身处一线互联网公司,虽没有直面过求职跳槽
  • 正式宣布:与台湾“断交”!

  • 当地时间3月25日,洪都拉斯外交部发表声明,正式宣布与中国台湾断绝“外交关系”。声明说,世界上只有一个中国,中华人民共和国是代表中国的唯一合法政府,台湾是中国领土不可分割的
  • 看一张触目惊心的知乎截图

  • 1,曾哥记得非常清楚,有一个知乎问题,之前我是写过回答的,只不过,写完了以后,没有发不出来。至于为什么没有发不出来,没有其他别的什么原因,仅仅是因为自己对于自己的要求,实在是太高

热门文章

  • “复活”半年后 京东拍拍二手杀入公益事业

  • 京东拍拍二手“复活”半年后,杀入公益事业,试图让企业捐的赠品、家庭闲置品变成实实在在的“爱心”。 把“闲置品”变爱心 6月12日,“益心一益·守护梦想每一步”2018年四

最新文章

  • 才发现你们都在用cdf会员购,后悔没早知道!

  • 去海南/香港旅行,难免要逛逛免税店,免税和含税的价格确实相差太多,都是大家血拼剁手的时刻。中免已开通了好几个线上商城,可真是福利啊,再也不用找人代购了!还有cdf会员购海南商城
  • 明天19:30!2023交通安全课来啦!附直播入口~

  • 交通安全关系着孩子的生命健康以及千家万户的幸福平安出行是孩子的终生必修课交通安全教育应从小做起2023交通安全课来啦赶紧带着自家小朋友一起看!“知危险 会避险”交通安
  • Flutter中的异步执行策略

  • 点击上方蓝字关注我,知识会给你力量在Flutter中,如何执行一段延迟执行的异步代码?我们可以找到下面这些方法。scheduleMicrotaskFuture.microtaskFutureFuture.delayedTimer.ru