当前位置: 首页 > 知识库问答 >
问题:

Android:从另一个线程将一个可运行的线程发布到主线程上实际上是干什么的?

巫马俊力
2023-03-14

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

我问这个问题的主要原因是,我可以更好地理解需要记住哪些注意事项,以防止由于多线程而导致的错误。(特别是旧请求影响已经刷新的页面的情况)

共有1个答案

东门佐
2023-03-14

首先,您需要了解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]标记的东西表示处理消息的两种不重叠的方法。如果回调不为空,则忽略所有[SWITCHED]字段。如果回调为空,则消息由[SWITCHED]字段定义,并在处理程序的重写的handlemessage()处理程序的handlemessage()中处理。

MessageQueueWhen字段排序。looper不会出列并处理消息,直到由SystemClock.uptimeMillis度量的当前时间大于或等于消息的When字段中存储的时间。

当调用处理程序#post(可运行的r)时,会发生以下情况:

>

  • 从池中获得消息(message类中的简单静态链表)

    您的runnable被分配给消息的callback字段。

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

    消息进入消息队列。如果when早于队列头的head,它将成为一个新的head。如果不是,则将其插入中间,以便MessageQueue保持按When排序

    处理程序决定消息是[可运行的]还是[交换的]并相应地处理它。特别是,如果存在run(),则在callback上调用run()

    这将回答您关于阻塞任务期间发布在UI线程上的runnable行为的问题--嗯,不,它不会中断正在进行的任务,也不会交织。线程上发生的一切首先进入messagequeue、按钮单击或您从其他线程发布的自定义runnable。它基本上不可能以其他方式发生:looper.loop()只是让线程忙于其for(;;)循环。

    但是,有一些方法可以更改消息的顺序。

    此外,您还可以调用一个自解释的处理程序#postatfrontofqueue(),正如文档中所指出的那样

    这种方法只用于非常特殊的情况--它很容易使消息队列处于饥饿状态,导致排序问题,或者产生其他意想不到的副作用。

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

  •  类似资料:
    • 问题内容: 因此,正如标题所述:将可运行对象从另一个线程发布到主线程时,实际上会发生什么? 我已经看到很多问题,询问您如何执行以及其基本原理。但是,当您将可运行对象放在MessageQueue上时,我很难找到确切的解释。当然,它在轮到Runnable时运行。但是什么时候呢? 因此,例如: 假设有一个按钮启动ASync请求,并且该请求返回并触发在MainThread上运行的可运行/回调。怎么了?可运

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

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

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

    • 我如何启动两个线程,其中thread1首先执行,thread2在thread1结束时启动,而主方法线程可以在不锁定其他两个线程的情况下继续工作? 我尝试了join(),但是它需要从线程调用,线程必须等待另一个线程,没有办法执行类似thread2.join(thread1)的操作;因此,如果我在main()中调用join,我将有效地停止主线程的执行,而不仅仅是Thread2的执行。 #编辑:为什么我

    • 我试着运行一个程序,使用线程显示带有数字的乘法、除法、加法和减法表。 但是我希望数字被乘以或相加等。由用户选择。 也就是说,程序应该在用户为每个操作选择一个数字后运行,然后显示结果。