appinventor 中ui线程,事件队列,后台函数与回调函数,
此处加入ai2 wxbit作者的回答
“【假装群主】皮皮蟹 11:49:13
事件优先级的理解不对。ui线程只有一个,事件就是在ui线程里,代码块顺序运行。后台运行和循环运行都是新开线程。回调必然要等完成事件之后
【假装群主】皮皮蟹 11:55:46
除非事件里抛出异常,正在运行的事件块不会被打断。但是可能会插入“出现错误”事件。比如在点击事件读文件,如果出错就转到文件管理器的出错事件,之后再回到点击事件”
在ai2中使用一些耗时操作,比如打开文件,调用http客户端获得响应,使用数据库,这些都是异步操作,得到结果后运行回调函数,但是运行这些异步回调函数操作UI可能会得到非预想的结果。原因是主UI线程在事件处理队列列中优先级比回调函数高。
先摘录mit ai2的原文:Android UI线程,它负责响应UI交互(例如按钮按下)和更新UI。所有用户代码和大多数组件库代码都在UI线程中运行。 (稍后,我们将讨论由于用户操作而创建线程。)这为用户提供了一个简单的执行模型:App Inventor过程永远不会被事件处理程序中断,反之亦然; 一个事件处理程序也不会被另一个事件处理程序中断。UI线程在安卓中是主线程。

图1:演示串行语义的示例程序。执行Button1.Click时,两个Ball放在相同的位置,导致事件处理程序Ball1.CollidedWith被添加到调度队列中。但是,在第一个处理程序完成之前,无论未示出的用户过程等待多长时间,它都不会被执行 。
最终的标签显示始终是:“... Button1.Click ...... Ball1.CollidedWith ......”。
在wxbit汉化版中,这里用一个循环模拟延时操作,如果是一个事件里的耗时操作如下图,实测在耗时操作完成后才会先运行按钮其他点击事件(并且先运行耗时循环操作,再按代码顺序运行操作,并不是这个耗时操作会按代码顺序会在中间运行。原因:循环运行会新开线程),再运行精灵碰撞事件。最终的标签会标签文本显示 “按钮一执行完毕球形精灵碰撞。、”

但是! wxbit的延迟调用函数是后台运行的,如果这么写

运行结果就是标签变成 “按钮点下球形碰撞”,然后2秒后再加上“按钮一执行完毕”。注意wxbit这里这个延迟调用函数放在后台运行的,在事件运行队列里会在UI主线程的事件运行完之后才运行。

继续研究下ai2中的事件调度队列,ui线程永远不会被组件的事件打断,ui线程也不会打断组件的事件处理过程。但是ui在事件队列里比组件的事件先运行。看如下代码

如果快速点击按钮1,会发现一开始按钮按下次数与精灵碰撞次数都不对,然后等一会,先是按钮按下次数变成正确数,然后是碰撞次数显示正确,显示一串的球形碰撞。说明精灵碰撞事件是在按钮按下事件队列处理完了之后才会运行。所以导致标签文本出现多次连接字符串“球形碰撞”
如果用wxbit的后台调用更新ui,会导致不一样的结果

这时候如果快速点击按钮1,执行完毕这四个字会照按钮点了多少次出现,但是精灵碰撞次数就对不上按钮点击次数了。此时按钮的点击事件作为高优先级事件先运行,打断了 调用球形精灵移动, 精灵移动被放入事件队列在按钮点击运行完成后才运行,证明在主UI线程组件的事件优先级高。
最后使用回调函数

结果是一样的。结果精灵碰撞次数仍然是对不上按钮点击次数的。
继续测试,在回调函数中统计调用次数

实验调用次数与精灵移动次数都跟按钮次数能对的上,证明回调函数确实运行次数正确,只是因为按钮的点击事件优先级高,所以会先运行移动精灵到50,50. 按钮的事件队列运行完了才会运行回调函数里的移动精灵到60,60.。所以碰撞次数就没有按钮点击次数多。

浙公网安备 33010602011771号