所以,正如标题所说:当你将另一个线程的runnable发布到主线程上时会发生什么?
我已经看到很多问题,询问你是如何做到这一点的,以及它的基础知识是如何运作的。但是,当你在MessageQueue上放置一个runnable时,我很难找到确切的解释。肯定是它在Runnable转弯时运行。但这是什么时候?
所以例如:
假设有一个启动ASync请求的按钮,请求返回并触发在MainThread上运行的runnable / callback。怎么了? runnable被添加到MessageQueue并在'time'时运行。但是什么时候到了?如果我在Async请求发布MainThread上的runnable之前按下另一个在MainThread上执行半长阻塞任务的按钮怎么办?是否等到我的阻止按钮上的逻辑完成?它会打断它吗?它是否将可运行代码与我的阻塞代码按钮的代码交织在一起?究竟发生了什么?
我问的主要原因是,我可以更好地了解我需要考虑哪些因素来防止多线程导致的错误。 (特别是影响已刷新页面的旧请求的情况)
答案 0 :(得分:4)
首先,您需要了解Message
类是什么样的。 Message
对象包含以下字段:
Handler target; // a handler that enqueued the message
long when; // the time at which the message is to be processed
[RUNNABLE] Runnable callback; =
[SWITCHED] int what, int arg1, int arg2, Bundle data...
bool isAsynchronous; // I will talk about it in the end
我用 [RUNNABLE] 和 [SWITCHED] 标记的内容代表处理Message
的两种非重叠方式。如果callback
不为空,则忽略所有 [SWITCHED] 字段。如果callback
为空,而Message
由 [SWITCHED] 字段定义,则会在Handler's
覆盖handleMessage()
或{使用。{/ p>初始化handleMessage()
处理程序的{1}}
Handler.Callback
按MessageQueue
字段排序。在when
衡量的当前时间大于或等于消息的Looper
字段中存储的时间之前,SystemClock.uptimeMillis
不会出列消息并处理消息。
当您致电when
时,会发生以下情况:
从池中获取Handler#post(Runnable r)
(一个简单的静态链表
在Message
类)
您的Message
被分配到邮件的Runnable
字段。
callback
字段只是设置为当前时间
时间过去了
when
已加入Message
。如果是MessageQueue
它比队列的头部更早成为一个新头。如果
它不是,而是插在中间,以便when
仍按MessageQueue
when
处于非终止循环中的队列消息
从队列中按顺序处理它们(没有交织),
最终,我们的消息出列并致电Looper
最初发布dispatchMessage()
。
处理程序决定邮件是否为 [RUNNABLE] 或
[SWITCHED] 并相应地处理它。特别是它打电话
Runnable
上的run()
(如果有)
这应该回答你关于在阻止任务期间发布在UI线程上的callback
行为的问题 - 好吧,不,它不会中断正在进行的任务,也不会交织。首先在线程上发生的一切都会进入Runnable
,按钮点击或您从其他线程发布的自定义MessageQueue
。基本上没有办法以其他方式发生:Runnables
只是让线程忙于其Looper.loop()
循环。
有很多方法可以更改订阅消息。
例如,Looper / Handler框架中有一个有趣的同步屏障概念。一个惯例只是一个for(;;)
同步障碍Message
(所以它基本上只是一个类似于旗帜的东西,没有处理程序来调度它)。如果将其放入target
的队列中,则整个队列的更改将更改,直到同步屏障从postSyncBarrier()
的队列中删除。未标记为removeSyncBarrier()
的{{1}}将被忽略,并且不会出列和处理。而是扫描队列,直到找到Messages
的消息。然后根据其isAsynchronous
进行安排,并在时机到来时进行处理。
此外,您可以调用一个不言自明的isAsynchronous = true
,但正如文档中所指出的那样
此方法仅适用于非常特殊的情况 - 它可以 容易使消息队列饿死,导致排序问题,或者有 其他意想不到的副作用。
我建议你浏览所提到的所有课程的source code。它读起来就像一本好书。
答案 1 :(得分:1)
MainThread执行了许多其他runnable,例如更新UI,触摸事件。 '时间'是发布的runnable准备好出列的时间。如果任何其他runnable出现在它之前,你的runnable将等待。
这里没有中断这样的事情。你的按钮将提交一系列runnables,就像从许多不同的线程中提交相同数量的runnable一样。
如果你有一条非短消息(任何包含LONG字对UI不好的话),操作将阻止队列中提交的其他重复任务的执行,大多数情况下经常证明没有更新(对于任务执行是如果是执行时间超过8毫秒的可运行的突发问题,那么在UI上完全或不确定。