Android源码系列一:Handler源码剖析
2019-05-27 本文已影响6人
Taonce
利用Handler实现异步的完整操作
// 创建一个Handler的子类,实现handlerMessage()方法
inner class MyHandler : Handler() {
override fun handleMessage(msg: Message?) {
Log.d("taonce", msg?.arg1.toString())
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val myHandler = MyHandler()
thread {
// 获取Message对象,尽量使用obtainMessage()来创建消息对象,这样会循环利用消息池中的对象,避免重复创建
val msg = myHandler.obtainMessage()
msg.arg1 = 1
// 发送消息
myHandler.sendMessage(msg)
}
}
创建 Handler
的对象,利用该对象获取 Message
对象,然后通过 sendMessage(msg)
发送消息,最后在 handlerMessage(msg)
方法里面处理收到的消息。
下面是 Handler
简单的流程图:
Handler 发送消息
-
创建
Handler
对象:public Handler(Callback callback, boolean async) { // 检查是否存在内存泄漏的情况 if (FIND_POTENTIAL_LEAKS) { final Class<? extends Handler> klass = getClass(); if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && (klass.getModifiers() & Modifier.STATIC) == 0) { Log.w(TAG, "The following Handler class should be static or leaks might occur: " + klass.getCanonicalName()); } } // 获取 Looper mLooper = Looper.myLooper(); if (mLooper == null) { // 以后使用 Handler 的过程中出现这个异常就知道没有获取到 Looper throw new RuntimeException( "Can't create handler inside thread " + Thread.currentThread() + " that has not called Looper.prepare()"); } // 获取 MessageQueue mQueue = mLooper.mQueue; mCallback = callback; mAsynchronous = async; }
-
发送消息:使用
sendMessage(Message msg)
发送消息,最终都会走到sendMessageAtTime(Message msg, long uptimeMillis)
,下面来看看它的源码部分:public boolean sendMessageAtTime(Message msg, long uptimeMillis) { // 获取 MessageQueue MessageQueue queue = mQueue; if (queue == null) { RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue"); Log.w("Looper", e.getMessage(), e); return false; } // 调用 enqueueMessage() 方法 return enqueueMessage(queue, msg, uptimeMillis); }
一起来看看
enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis)
源码部分:private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { // 将当前的 Handler 赋值给 msg.target msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } // 调用 MessageQueue 的添加操作,MessageQueue 不是队列而是单向链表 return queue.enqueueMessage(msg, uptimeMillis); }
跟着
MessageQueue
来添加新的Message
:boolean enqueueMessage(Message msg, long when) { if (msg.target == null) { throw new IllegalArgumentException("Message must have a target."); } if (msg.isInUse()) { throw new IllegalStateException(msg + " This message is already in use."); } synchronized (this) { // 如果是处于退出状态,那么回收此 Message if (mQuitting) { IllegalStateException e = new IllegalStateException( msg.target + " sending message to a Handler on a dead thread"); Log.w(TAG, e.getMessage(), e); msg.recycle(); return false; } msg.markInUse(); msg.when = when; // 这个 mMessage 是链表的表头 Message p = mMessages; boolean needWake; if (p == null || when == 0 || when < p.when) { // 如果p为空,或者需要立即处理,那么将链表的表头设置为 msg msg.next = p; mMessages = msg; needWake = mBlocked; } else { // 将 msg 插入到 MessageQueue 的尾巴中 needWake = mBlocked && p.target == null && msg.isAsynchronous(); Message prev; // 循环结束之后,prev 是链表的尾巴 for (;;) { prev = p; p = p.next; if (p == null || when < p.when) { break; } if (needWake && p.isAsynchronous()) { needWake = false; } } // 在尾巴后面加上 msg msg.next = p; prev.next = msg; } // We can assume mPtr != 0 because mQuitting is false. if (needWake) { nativeWake(mPtr); } } return true; }
Looper 循环消息
- 先看
Looper.loop()
源码:
接着我们来看看/** * Run the message queue in this thread. Be sure to call * {@link #quit()} to end the loop. */ public static void loop() { // 获取Looper对象 final Looper me = myLooper(); if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } // 获取MessageQueue对象 final MessageQueue queue = me.mQueue; // 重点是此处的死循环 for (;;) { // 接下来会介绍 MessageQueue 的链表拿消息的操作 Message msg = queue.next(); // 此处可能会造成阻塞 if (msg == null) { // 如果没有 Message 就代表可以退出此循环了 return; } // 此处省略了很多源码 try { // msg.target 也就是在 enqueueMessage(queue, msg, uptimeMillis) 中赋值的 Handler ,用它的 dispatchMessage(msg) 来分发消息 msg.target.dispatchMessage(msg); dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0; } // 回收 Message 对象 msg.recycleUnchecked(); } }
MessageQueue
的next()
方法:Message next() { int pendingIdleHandlerCount = -1; // -1 only during first iteration // nextPollTimeoutMillis 这个变量很重要,底层通过此变量来判断是否进行阻塞操作 // -1: 一直阻塞 // 0: 不阻塞 // >0: 阻塞指定的值,如果其中有唤醒操作则立马唤醒 int nextPollTimeoutMillis = 0; for (;;) { if (nextPollTimeoutMillis != 0) { Binder.flushPendingCommands(); } // 交给底层处理是否阻塞 nativePollOnce(ptr, nextPollTimeoutMillis); synchronized (this) { final long now = SystemClock.uptimeMillis(); Message prevMsg = null; // mMessage为链表的头结点,第一次拿到链表的头结点 Message msg = mMessages; // 如果msg的Handler为空,或者头结点为空,那么就去取下一个结点 if (msg != null && msg.target == null) { do { prevMsg = msg; msg = msg.next; } while (msg != null && !msg.isAsynchronous()); } if (msg != null) { // 延迟操作 if (now < msg.when) { nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE); } else { mBlocked = false; if (prevMsg != null) { prevMsg.next = msg.next; } else { // 头结点移到下一位 mMessages = msg.next; } // 清空msg的链路关系 msg.next = null; if (DEBUG) Log.v(TAG, "Returning message: " + msg); msg.markInUse(); return msg; } } else { // 没有消息,一直阻塞 nextPollTimeoutMillis = -1; } // Process the quit message now that all pending messages have been handled. if (mQuitting) { dispose(); return null; } // Reset the idle handler count to 0 so we do not run them again. pendingIdleHandlerCount = 0; // While calling an idle handler, a new message could have been delivered // so go back and look again for a pending message without waiting. nextPollTimeoutMillis = 0; }
处理消息
Handler
处理消息的源码很简单:
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
// msg的回调不为空,消息交给msg处理
// handler的回调不为空,消息交给Callbacl处理
// 上面都不满足的情况下,消息才交给我们通常看见的handlerMessage(msg)来处理
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
Handler
源码分析就到此结束,后面还会为大家分享 HandlerThread
和 IntentService
相关的源码系列,都是和 Handler
紧密联系的,也是大家日常高度使用和面试常问的知识点,获取更多的原创可关注我的公众号,下面是公众号二维码:
![](https://img.haomeiwen.com/i6297937/05d05f3ef91f10be.png)