安卓底朝天—— android.os.Handler.post::Runnable: 的调用栈
Handler 中可调用的函数有:
android.os.Handler.post::Runnable:
android.os.Handler.postAtTime::Runnable,long:
android.os.Handler.postAtTime::Runnable,Object,long:
android.os.Handler.postDelayed::Runnable,long:
android.os.Handler.postAtFrontOfQueue::Runnable:
android.os.Handler.sendMessage::Message:
android.os.Handler.sendEmptyMessage::int:
android.os.Handler.sendEmptyMessageDelayed::int,long:
android.os.Handler.sendEmptyMessageAtTime::int,long:
android.os.Handler.sendMessageDelayed::Message,long:
android.os.Handler.sendMessageAtTime::Message,long:
android.os.Handler.sendMessageAtFrontOfQueue::Message:
实际上,这些函数的里子是一样的,它们都调用了 enqueueMessage,看下图:
虽然这些函数有的接收一个 Runnable,有的接收一个 Message,但在实现中,Runnable 会变成 Message 的一个属性,从图中可以看出来,这是通过函数 getPostMessage 实现的,我们看一下函数的源码:
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
下面的图说明了你传入的 Runnable 是怎么传给属性 android.os.Message.callback 的。
因此无论你传入的是 Message 还是 Runnable,它都会存一个Message。
所有实际的工作是由函数:android.os.Handler.enqueueMessage::MessageQueue,Message,long: 做的,而它也只是把工作交给了函数:
android.os.MessageQueue.enqueueMessage::Message,long:,而且到这里 Handler 类已经没有东西了,除了下面这些我觉得不需要讲的:
android.os.Handler.obtainMessage:::
android.os.Handler.obtainMessage::int:
android.os.Handler.obtainMessage::int,Object:
android.os.Handler.obtainMessage::int,int,int:
android.os.Handler.obtainMessage::int,int,int,Object:
android.os.Handler.removeCallbacks::Runnable:
android.os.Handler.removeCallbacks::Runnable,Object:
android.os.Handler.removeMessages::int:
android.os.Handler.removeMessages::int,Object:
android.os.Handler.removeCallbacksAndMessages::Object:
函数 android.os.MessageQueue.enqueueMessage::Message,long:
将你传给的 message 存到了 Message 队列android.os.MessageQueue.mMessages 中,存的时候会按时间排序,而在函数 android.os.Looper.loop::: 中通过死循环不断的调用函数 android.os.MessageQueue.next::: 来从这个 Message 队列获取下一个 message,然调用函数 android.os.Handler.dispatchMessage::Message: 来处理消息。
函数 android.os.MessageQueue.next::: 里面也是个死循环,当消息队列中没有消息时,这个函数被函数 android.os.MessageQueue.nativePollOnce::long,int: 阻塞,当有消息但是队头的消息还没有到时间时,这个函数会在死循环中空转,一直等到第一个消息的时间到了的时候把这个消息返回。Handler 之所以可以延时执行,就是靠这个函数了。
函数 android.os.Handler.dispatchMessage::Message: 比较简单,可以直接上源码了:
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
dispatchMessage 这个函数根据情况在三个函数中三选一调用:
android.os.Handler.handleCallback::Message: (这个函数调用了 Handler.post::Runnable: 传入的 Runnable)
android.os.Handler.Callback.handleMessage::Message:(这个我就不知道了)
android.os.Handler.handleMessage::Message: (这个函数调用了自定义的 Handler.handleMessage::Message:)
现在我们可以总结了调用栈了,拿函数 android.os.Handler.post::Runnable: 为例:
android.os.Handler.post::Runnable:
android.os.Handler.sendMessageDelayed::Message,long:
android.os.Handler.sendMessageAtTime::Message,long:
android.os.Handler.enqueueMessage::MessageQueue,Message,long:
android.os.MessageQueue.enqueueMessage::Message,long:
。。。。。。。。。。。。。。Message 被存入消息队列。。。。。。。。。。。。。。。。。。。
android.os.MessageQueue.mMessages
android.os.Looper.loop:::
。。。。。。。。。。。。。。从消息队列中按时间获取消息。。。。。。。。。。。。。。。。。。
android.os.MessageQueue.next:::
。。。。。。。。。。。。。。。。。处理获取到的消息。。。。。。。。。。。。。。。。。。。。
android.os.Handler.dispatchMessage::Message:
android.os.Handler.handleCallback::Message: / android.os.Handler.handleMessage::Message:
顺便说一下,Looper 是如何让不同线程中使用不同 Looper 实例的
它使用了属性 android.os.Looper.sThreadLocal,这是个 java.lang.ThreadLocal 类型的属性,源码:
// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
当你想要得到一个 Looper 对象时,它调用了函数 java.lang.ThreadLocal.get:::,这个函数不论你在哪个线程调用,如果属性 sThreadLocal 存在于线程 A,它都会返回线程 A 中存放的实例。
因此在安卓开发中,你要在非 UI 线程更新 UI 的时候,Handler 对象必须是在 UI 线程获取的,因为 Handler 中有一个 Looper 类型的属性:android.os.Handler.mLooper,而 Loop 类有 MessageQueue 类型的属性,你存放消息的消息队列 MessageQueue 实例与 Looper 实例是一一对应的,下面这个图可以说明 enqueueMessage 函数存放消息的消息队列确实来自于 Looper 实例。
它能决定你 post 的 Runnable 或者 send 的 Message 存放在哪个 Looper 实例的 MessageQueue 中,也就是决定了你定义的回调函数在哪个 Looper 实例中运行,也就是决定了在哪个线程上运行。
再说一下Looper中消息队列和异步消息的理解
请你想像这样一个超市,超市里的顾客有毛病,非得按他们自己规定的时间结帐,如果因为前面顾客结帐时间太长而耽误了他们规定的结帐时间,对于顾客是可以接受的,但是时间不到,谁也不愿意结帐,这就是消息队列。
出于一种我也不知道为什么的原因,消息队列中有 barrier 的存在,它会阻塞队列的前进,但不会阻塞异步消息,这就是异步消息与同步消息的不同。
这些事情都是发生在函数 android.os.MessageQueue.next::: 中,想看实情的话可以去读这个函数的源码。