💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
new Handler().obtainMessage().sendToTarget()这句话用着真爽,一行代码就能搞定异步消息了!所以在代码中使用的算是非常频繁的了,那这又是一个什么样的过程呢? 这个过程中又有什么玄机呢? 这篇文章,我们来一步步的分析一下这三句话。 ### 1、new Handler()的分析 new Handler()会辗转来到public Handler(Callback callback, boolean async)这个构造方法。在这个构造方法中会获取当前Looper: ~~~ mLooper = Looper.myLooper(); ~~~ 而此时的Looper是默认的那个Looper,即在ActivityThread的main方法中prepare的Looper 在ActivityThread.main中: ~~~ Looper.prepareMainLooper(); ... Looper.loop(); ~~~ 此时Handler和Looper有了关联。 ### 2、obtainMessage()的分析 在Handler.obtainMessage()中会调用Message.obtain(this)。 Message.obtain()的源码: ~~~ public static Message obtain(Handler h) { Message m = obtain(); m.target = h; return m; } ~~~ obtain从消息池中构造一个message,并将message的target置为传进来的handler。 此时handler和message有了关联。 ### 3、sendToTarget()的分析 ~~~ public void sendToTarget() { target.sendMessage(this); } ~~~ 直接调用target.sendMessage,而target正是当前的Handler。 继续跟踪target.sendMessage(this) target中发送消息会辗转来到private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) 在这个方法中有去调用queue.enqueueMessage. 继续跟踪queue.enqueueMessage,这个方法有点长,主要是将当前Message压入消息队列中: ~~~ ... msg.when = when; Message p = mMessages; boolean needWake; if (p == null || when == 0 || when < p.when) { // New head, wake up the event queue if blocked. msg.next = p; mMessages = msg; needWake = mBlocked; } else { // Inserted within the middle of the queue. Usually we don't have to wake // up the event queue unless there is a barrier at the head of the queue // and the message is the earliest asynchronous message in the queue. needWake = mBlocked && p.target == null && msg.isAsynchronous(); Message prev; for (;;) { prev = p; p = p.next; if (p == null || when < p.when) { break; } if (needWake && p.isAsynchronous()) { needWake = false; } } msg.next = p; // invariant: p == prev.next prev.next = msg; } // We can assume mPtr != 0 because mQuitting is false. if (needWake) { nativeWake(mPtr); } ... ~~~ 这里面的MessageQueue就是在Handler保存的那个MessageQueue,也就是说此时,这个Message已经保存到Handler中的那个消息队列中了。而,我们Handler中的MessageQueue哪来的呢? 来看看这行代码: ~~~ public Handler(Callback callback, boolean async) { ... mLooper = Looper.myLooper(); ... mQueue = mLooper.mQueue; ... } ~~~ Handler中的MessageQueue正式从Looper中获取的,这个Looper当然就是在ActivityThread中prepare的那个。 顺一下此时的关系:Handler中保存了ActivityThread中的Looper,并从该Looper中获取了MessageQueue;调用obtainMessage,实质上是创建了一个Message对象,并将Message对象的target设置为现在的Handler;调用Message.sendToTarget()实际是调用了Message.target.sendMessage(),即Handler.sendMessage,而Handler.sendMessage会来到enqueueMessage方法,在这个方法中调用MessageQueue.enqueueMessage将消息压缩刚开始我们获取的那个MessageQueue。 此时,再来看看Looper.loop()是怎么将消息回调到handleMessage中的: ~~~ for (;;) { Message msg = queue.next(); // might block ... msg.target.dispatchMessage(msg); ... msg.recycle(); } ~~~ 继续看看Handler.dispatchMessage(): ~~~ public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } } ~~~ 转来转去,终于把Message回调到了handleMessage!!! 从源码中,我们也能看出, sendToTarget()方法并不是真正的将Message发送出去,而是将Message压入了MessageQueue中,真正去回调handleMessage还是在Looper.loop()中完成的。