rog*_*rkk 39 multithreading android android-handler android-looper
我试图绕过线程,我知道我可以使用a Handler来发送消息/ runnables MessageQueue,然后由它接收Looper并发送回处理程序进行处理.
如果我发布到一个处理器在我的活动,是Activity,Handler,MessageQueue并且Looper在UI线程上所有正在运行的?如果没有,有人可以解释这一切是如何结合在一起的吗?:)
use*_*618 65
简短回答:它们都在同一个线程上运行.如果从Activity生命周期回调中实例化,它们都在主UI线程上运行.
答案很长:
一个线程可能有一个Looper,其中包含一个MessageQueue.为了使用这个工具,你必须Looper通过调用(静态)在当前线程上创建一个Looper.prepare(),然后通过调用(也是静态)来启动循环Looper.loop().这些是静态的,因为Looper每个线程只应该有一个.
loop()通常,调用通常不会返回一段时间,但会继续将消息("任务","命令"或任何您喜欢的内容)调出来MessageQueue并单独处理它们(例如通过回调Runnable消息中包含的内容).当队列中没有剩余消息时,线程会阻塞,直到有新消息.要停止a Looper,你必须调用quit()它(它可能不会立即停止循环,而是设置一个私有标志,从循环中定期检查,标志它停止).
但是,您无法直接向队列添加消息.相反,您注册a MessageQueue.IdleHandler等待queueIdle()回调,您可以在其中决定是否要做某事.所有处理程序依次被调用.(因此"队列"实际上不是一个队列,而是定期调用的回调集合.)
关于前一段的注意事项:我实际上已经猜到了.我找不到任何关于这方面的文件,但这是有道理的.
因为这是很多工作,所以框架提供了Handler简化事物的类.创建Handler实例时,它(默认情况下)绑定到Looper已连接到当前线程的实例.(该Handler知道什么Looper附加到,因为我们叫prepare()早,这可能存储在参考Looper的ThreadLocal.)
使用a Handler,您可以调用post() "将消息放入线程的消息队列"(可以这么说).在Handler将采取所有关心IdleHandler回调的东西,请确保您的发布Runnable执行.(如果您延迟发布,它也可能会检查时间是否正确.)
只是要清楚:真正让一个线程循环的唯一方法做事情是要发布一条消息到它的循环.这在你在looper上调用quit()之前一直有效.
关于android UI线程:在某些时候(可能在创建任何活动之前),框架已经设置了一个Looper(包含一个MessageQueue)并启动它.从这一点开始,UI线程上发生的一切都是通过该循环.这包括活动生命周期管理等.您覆盖的所有回调(onCreate(),onDestroy()...)至少是从该循环中间接调度的.例如,您可以在异常的堆栈跟踪中看到.(你可以尝试一下,只是写int a = 1 / 0;在onCreate()......)
我希望这是有道理的.很抱歉以前不清楚.
ahc*_*cox 11
跟进"如何一起来"这个问题的一部分.正如user634618所写,looper接管一个线程,在应用程序main的情况下接管主UI线程Looper.
Looper.loop()将消息从其消息队列中拉出.每个Message都有一个对应关联的Handler的引用,它将被返回给(目标成员).Looper.loop()从队列中获取的每条消息的内部:
loop()public void Handler.dispatchMessage(Message msg)使用存储在Message中的Handler作为其目标成员进行调用.handleMessage()以Message作为参数调用.(注意,如果您将Handler子类化为AsyncTask,则可以覆盖handleMessage()它.)关于所有协作对象在同一UI线程上的问题,Handler必须在与Looper发送消息的线程相同的线程上创建.它的构造函数将查找当前Looper并将其存储为成员,将其绑定Handler到该成员Looper.它还将Looper直接在其自己的成员中引用该消息队列.该Handler可用于发送工作到Looper从任何线程,但该消息的这个身份排队路由进行了所做的工作Looper的线程.
当我们在另一个线程上运行一些代码并想要在UI线程上发送Runnable时,我们可以这样做:
// h is a Handler that we constructed on the UI thread.
public void run_on_ui_thread(final Handler h, final Runnable r)
{
// Associate a Message with our Handler and set the Message's
// callback member to our Runnable:
final Message message = Message.obtain(h, r);
// The target is the Handler, so this asks our Handler to put
// the Message in its message queue, which is the exact same
// message queue associated with the Looper on the thread on
// which the Handler was created:
message.sendToTarget();
}
Run Code Online (Sandbox Code Playgroud)