
百度百科告诉我们,驱动即用推动,事件驱动就是用一个个的事件,推动某个 *** 作的执行。
2. Loop在我们的Java编程的程序系列中,AndroID就是一个典型的事件驱动应用,熟悉AndroID开发的同学一定知道,其底层不断地有一个Looper在循环,遇到消息则处理,否则阻塞在MessageQueue.next()方法处。我们非常常用的一个方法:runOnUiThread的作用是在主线程执行一个 *** 作,因为在子线程安卓系统不允许我们 *** 作UI。但是你想过他是如何实现的吗?
其实很简单:
public final voID runOnUiThread(Runnable action) { if (Thread.currentThread() != mUiThread) { mHandler.post(action); } else { action.run(); }}判断一下当前线程是否主线程,是的话直接执行,否则的话,通过Handler机制,post到主线程,然后由子线程的Looper取出执行。
比如我们在请求网络后,想让系统加载一个数据,数据返回后,更新视图,那么“数据返回”实际上就是一个事件,既然是事件我们肯定要消费,所以就调用runOnUiThread交给主线程消费。
其实,我们在任何一个主线程的调用栈中,调用栈底的方法一定是loop方法,因为所有发生在主线程的 *** 作都是先给主线程的MessageQueue加入一个Message,然后looper取出执行 *** 作,Message甚至可以附带一个Runnable来执行代码。也可以附带一些信息,在回调处统一处理。
3. OnClickListener 事件我们通常会调用VIEw下的setonClickListener设定点击事件,比较常见的写法除了简单的设置VIEw.OnClickListener、XML指定以外,通常是使用当前的Activity去实现VIEw.OnClickListener接口,重写onClick方法,根据ID来判断点击事件产生的对象,进而确定具体的点击事件。
比如设置一个按钮,我们点击按钮就要请求网络,那么点击事件就会作为请求网络的驱动,这就是一个非常简单的事件驱动的流程。
事件驱动模型有三个要素:事件源,监听器,事件。熟悉设计模式的同学应该很快就能反应过来,这三要素和Observer模式中的三个构成非常相似。实际上事件驱动模型就是基于观察者而定制的。
事件驱动模型的工作步骤:
定义监听器,为每一个事件编写处理方法。将监听器对象注册给事件源事件源发生某个事件时,调用监听器中对应的方法完成事件的处理。以上的3步,在OnClick事件中,分别对应:
//1\. 监听器,处理响应事件 val events = VIEw.OnClickListener { Toast.makeText(this@MainActivity,"HelloWorld!",Toast.LENGTH_SHORT).show() } //2\. 注册到事件源 findVIEwByID<TextVIEw>(R.ID.tv).setonClickListener (events) //3\. 当我们手指点击屏幕,产生事件时(即事件源产生事件),就向着目标分发事件,最终被触摸到的VIEw所消费。5. Dart和Flutter(这部分的内容主要来自泪已无痕:[译] Flutter 异步编程:Future、Isolate 和事件循环,原文更详细,这里是完全参考着他写的,详细了解建议看原文。)
Dart是单线程模型,而Flutter则依赖于Dart,单线程模型有一个问题:同一时间执行一个 *** 作,而其他的 *** 作只能再其之后执行。
我们知道在AndroID中不能写死循环,否则会导致ANR,而Flutter也是一样,在Dart中如果我们写一个很大的for循环,那么在循环中执行 *** 作同样会导致线程的阻塞,界面也被阻塞,例如在重写的setState()中执行循环,则必须等到结束后才能加载出界面。
但是在如今纷繁复杂的业务逻辑要求中,我们单线程模型实际上很难满足各种各样的需求了。所以,Dart采用了了一个代码序列器(事件循环)。
当我们启动一个DartApp时,将会构建一个新的线程进程,在Dart中为Isolate,该线程将是你在整个应用中唯一需要关注的。
所以,此线程创建后,Dart将会自动地:
初始化2个FIFO队列(MicroTask和Event)并且当该方法执行完成后,执行Main方法启动事件循环事件循环是一种无限循环,在每个时钟周期内,如果没有其他的Dart代码执行,则:
voID eventLoop(){ while (microTaskQueue.isNotEmpty){ fetchFirstMicroTaskFromQueue(); executeThisMicroTask(); return; } if (eventQueue.isNotEmpty){ fetchFirstEventFromQueue(); executeThisEventRelatedCode(); }}从先后顺序我们可以看出,MicoTask队列优先于Event队列。
MicroTask队列用于非常简短且需要异步执行的的内部动作,这些动作需要在其他事件完成后 并 在将执行权交给Event队列之前运行。
Event 队列适用于以下参考模型:
IO手势绘图计时器流futures事实上,每次外部事件被触发时,需要执行的代码都会被Event队列所引用。一旦没有MicroTask运行,事件循环将考虑Event队列中的第一项并执行它,而Future *** 作也将由Event队列执行。
Future是一个异步执行并且在未来某一个时刻完成或者失败的任务,当实例化一个Future时:
该Future的实例被创建、并记录在由Dart管理的内部数组中。需要由此Future执行的代码直接推送到Event中。该Future实例返回一个状态(=incomplete)如果存在下一个同步代码,则执行它。只要事件循环从Event循环中获取它,被Future引用的代码将像其他任何Event一样执行。
当改代码将被执行完成(或者失败)时,then或者cacheError回调将被触发。
在如下例子中:
voID main(){ print('Before the Future'); Future((){ print('Running the Future'); }).then((_){ print('Future is complete'); }); print('After the Future');}输出的顺序:
Before the FutureAfter the FutureRunning the FutureFuture is complete执行的流程:
print(‘Before the Future’)将 (){print(‘Running the Future’);} 添加到 Event 队列;print(‘After the Future’)事件循环获取(在第二步引用的)代码并执行它当代码执行时,它会查找 then() 语句并执行它所以,Flutter/Dart是使用Event循环机制来模拟并发的请求的。
Aysnc方法在使用时,Dart会认为该方法的返回值是一个Future,它同步执行该方法,直到遇到第一个await关键字,然后它暂停该方法其他部分的执行,一旦await关键字引用的Future执行完成,下一行代码将立即执行。
例如这个例子:
voID main() async { methodA(); await methodB(); await methodC('main'); methodD();}methodA(){ print('A');}methodB() async { print('B start'); await methodC('B'); print('B end');}methodC(String from) async { print('C start from $from'); Future((){ // <== 该代码将在未来的某个时间段执行 print('C running Future from $from'); }).then((_){ print('C end of Future from $from'); }); print('C end from $from');}methodD(){ print('D');}从Main方法开始执行,遇到第一个await则暂停,按照以往的认知,打印应该是:
AB startC start from BC running Future from BC end of Future from BC end from BB endC start from AC running Future from AC end of Future from AC end from AD但是其实是:
AB startC start from BC end from B--- C中的Future代码会在之后执行,不会立即执行。B endC start from mainC end from mainD---到此处代码执行完了,才开始执行Event中的代码C running Future from BC end of Future from BC running Future from mainC end of Future from main这和我们想象的多线程(异步)处理有点不一样,异步只是线程各自以未知的顺序向前推进,但是单线程的Dart依靠事件循环机制,模拟了异步 *** 作,但是我们发现所有的Future都放到了代码的最后执行。预测程序执行变得非常困难。
我们又知道,await会阻塞在当前代码的位置,所以,await和Future配合使用,可以获得同步的效果,即该代码等到Future执行完了再向下执行:
methodC(String from) async { print('C start from $from'); await Future((){ // <== 在此处进行修改 print('C running Future from $from'); }).then((_){ print('C end of Future from $from'); }); print('C end from $from');}这样一来,可能在C start之后,等到C执行完成再向下执行。
所以,Dart中的异步执行实际上只是按照Event的事件处理规则执行,并不是真正的异步执行:
5.4 Isolate那么Flutter/Dart有自己的线程吗?Isolate。
Isolate在Flutter中不共享内存,不同的Isolate之间通过消息进行通信。
而每个Isolate都有自己的事件循环及队列(MicroTask和Event),这就意味着一个Isolate中运行的代码和另外一个Isolate不存在任何的关联。
是不是有点像Loop。
5.4.1 如何启用Isolate呢?我们需要在调用者和新的Isolate之间建立通信。
每个Isolate都暴露了一个将消息传递给Isolate的被称为SendPort的端口(这是一个监听端口,不是用来发送的)。
这意味着调用者和new Isolate需要知道彼此的端口才能进行通信。@H_722_301@ 我们有了端口就能发送消息,最后记得在dispose中销毁即可。
这是一种单工的通信方式(单监听流),我们只能从一方听到另一方发送的消息,如果要实现双工的通信需要彼此之间建立两条监听流。
5.5 结论Flutter的事件循环机制有点像AndroID线程的Looper,但是Dart是单线程的,而Future和Isolate则可以实现或者是模拟异步 *** 作,在开发中有非常重要的作用。
Flutter学习进阶——开发环境搭建和测试
每一个移动开发者都在为 Flutter 带来的“快速开发、富有表现力和灵活的 UI、原生性能”的特色和理念而痴狂,从超级 App 到独立应用,从纯 Flutter 到混合栈,开发者们在不同的场景下乐此不疲的探索和应用着 Flutter 技术,也在面临着各种各样不同的挑战。
本篇知识要点:
1、Flutter跨平台开发概述2、windows中Flutter开发环境搭建3、编写你的第一个Flutter APP4、Flutter Dart语言系统入门完整学习笔记pdf免费分享,需要的朋友只需要点赞支持一下后,【点击这里直达免费获取方式】 总结以上是内存溢出为你收集整理的Android开发—Flutter 中的事件驱动【附:Flutter开发环境搭建和测试全套PDF资料】全部内容,希望文章能够帮你解决Android开发—Flutter 中的事件驱动【附:Flutter开发环境搭建和测试全套PDF资料】所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)