当前位置: 首页 > 面试题库 >

Android:将可运行对象从另一个线程发布到主线程上实际上有什么作用?

钱经业
2023-03-14
问题内容

因此,正如标题所述:将可运行对象从另一个线程发布到主线程时,实际上会发生什么?

我已经看到很多问题,询问您如何执行以及其基本原理。但是,当您将可运行对象放在MessageQueue上时,我很难找到确切的解释。当然,它在轮到Runnable时运行。但是什么时候呢?

因此,例如:
假设有一个按钮启动ASync请求,并且该请求返回并触发在MainThread上运行的可运行/回调。怎么了?可运行对象被添加到MessageQueue并在“时间”运行。但是什么时候是“时间”?如果我在Async请求在MainThread上发布可运行对象之前按下另一个在MainThread上执行一些半长阻塞任务的按钮怎么办?它会一直等到阻止按钮上的逻辑完成吗?它会打断吗?它是否将可运行代码与我的阻止代码按钮的代码交织在一起?到底会发生什么?

我问的主要原因是,这样我可以更好地了解为防止多线程错误而需要牢记的注意事项。(特别是旧请求影响已经刷新的页面的情况)


问题答案:

首先,您需要了解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] 标记的
代表两种处理a的非重叠方式Message。如果callback不为null,则将忽略所有 [SWITCHED]
字段。如果callback为空比Message由下式定义 [SWITCHED]
字段和在任一处理Handler's被覆盖的handleMessage()handleMessage()所述的Handler.Callback处理程序与被初始化。

MessageQueue由分类when字段。该Looper不会出列并处理消息,直到当前时间,如由测量的SystemClock.uptimeMillis,大于或等于存储在消息的时间when字段。

当您致电时Handler#post(Runnable r),会发生以下情况:

  1. Message从池中获得A (类中的简单静态链接列表Message

  2. Runnable已分配到消息的callback字段。

  3. when 如果没有延迟或未经过特定时间,则将字段简单地设置为当前时间

  4. Message排队到MessageQueue。如果when早于队列头的时间,它将成为新的头。如果不是,则将其插入中间,以便MessageQueuewhen

  5. Looper这是一个非终止循环从队列中出队中的消息并处理它们在序列(无交织),最终,我们出队的消息,并呼吁dispatchMessage()在处理程序,最初发布的Runnable

  6. 处理程序确定消息是 [RUNNABLE] 还是 [SWITCHED], 并进行相应处理。特别 run()callback如果存在

这应该回答您有关Runnable阻塞任务期间在UI线程上发布行为的问题-好的, 不,它不会中断正在进行的任务,也不会交织
。线程上发生的所有事情首先进入MessageQueue,按钮单击或Runnables从其他线程发布的自定义。基本上没有任何其他方式可以发生这种情况:Looper.loop()只是使线程忙于其for(;;)循环。

虽然有一些方法可以更改消息的顺序。

例如,在Looper /
Handler框架中有一个有趣的同步屏障概念。按照惯例,同步屏障只是一个Message带有null的target(因此,它基本上只是一个类似于标志的东西,没有处理程序可以分派它)。如果将其放入队列中postSyncBarrier(),则出队的整个过程都会更改,直到使用将该同步屏障从队列中移除为止removeSyncBarrier()。在Messages没有被标记为isAsynchronous将在所有被忽略,不会出队并进行处理。而是将扫描队列,直到isAsynchronous = true找到带有的消息。然后将根据when其时间安排并在时间到来时对其进行处理。

另外,您可以Handler#postAtFrontOfQueue()根据文档中的说明调用不言自明的

此方法仅在非常特殊的情况下使用-它很容易使消息队列饿死,导致订购问题或产生其他意外的副作用。

我建议您浏览提到的所有类的源代码。它读起来就像一本好小说。



 类似资料:
  • 例如: 假设有一个按钮启动异步请求,该请求返回并触发主线程上运行的runnable/callback。会发生什么?runnable被添加到MessageQueue中,并在“时间”到时运行。但是什么时候是“时间”呢?如果在异步请求将runnable发布到MainThread之前,我按下另一个按钮,在MainThread上执行一些半长的阻塞任务呢?它会等到我的阻塞按钮上的逻辑完成吗?会打断它吗?它是否

  • 问题内容: 我真的对python中的sys.exit()感到困惑。在python文档中,它说“从Python退出”;这是否意味着在python程序中被调用时,进程将退出?如果是这样,下面的代码将显示不同的结果: 在linux中启动该程序,结果不是python文档所说的预期结果,但仍然可以在系统中运行,那么,真正的作用是什么? 问题答案: 根据文件提出: 通过提高SystemExit(status)

  • 问题内容: 我的一项活动遇到了一个奇怪的问题。从拍照/录像回来时,我正在显示一个对话框,允许用户命名相机。用户按下“确定”后,我将使用所请求的文件名发送给主题,该主题将复制文件(并显示进度对话框)。 由于某种原因,即使我调用,总是在主线程上调用执行复制的函数。 更改呼叫以解决问题。我还是想知道为什么它不起作用… 问题答案: 并且是那里最混乱的运营商。前者确保订阅副作用在指定的调度程序(线程)上发生

  • 在一个android服务中,我创建了用于执行一些后台任务的线程。 我遇到一个情况,线程需要在主线程的消息队列上发布特定任务,例如。 有没有方法获取主线程的并从我的另一个线程向它发布/?

  • 我有一个单独的线程在后台运行在C中,我希望它能够发布代码,在另一个已经运行android的线程上运行。操作系统。活套(例如主线)。我所说的“post”是指类似于视图post的东西,其中可运行的排队在事件循环上运行。将要执行的代码也用C编写。 我找到了ALooper API(http://developer.android.com/ndk/reference/group___looper.html)

  • 我创建了两个类来计算数字,其中一个类同步执行,另一个类将其分成两半,并在两个线程中执行这两半。(intel i5(4个CPU),8GB ram)代码如下: 公共类: 多线程执行:public class Sheet2{