Handler运行机制梳理
我们在使用Handler的时候,往往是这样一个使用步骤:
1. 初始化一个Handler对象,重写其handleMessage方法
2. 获取一个Message对象,并相应的为其what、obj属性赋值
3. 调用Handler.sendMessage(msg)方法发送消息
4. 发送出来的消息,将在Handler的handleMessage方法中进行处理
因此,我们从sendMessage方法看Handler执行了什么逻辑:
源码路径:frameworks\base\core\java\android\os\Handler.java
public final boolean sendMessage(Message msg) { return sendMessageDelayed(msg, 0); }
……
public final boolean sendMessageDelayed(Message msg, long delayMillis) { if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); }
……
public boolean sendMessageAtTime(Message msg, long uptimeMillis) { boolean sent = false; MessageQueue queue = mQueue; if (queue != null) { msg.target = this; sent = queue.enqueueMessage(msg, uptimeMillis); } else { RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue"); Log.w("Looper", e.getMessage(), e); } return sent; } |
由代码可知,sendMessage和sendMessageDelayed实际上都是调用了sendMessageAtTime方法。
若是采用sendMessage方法发送的消息,则uptimeMillis的值=当前时间;
若采用sendMessageAtTime方法发送消息,则uptimeMillis的值=当前时间+ delayMillis。
注意“msg.target = this;”这行代码,this在这里指的自然是发送这个Message的Handler对象,这行代码非常重要,在后面我们会遇到。
最终,我们是通过“queue.enqueueMessage(msg,uptimeMillis);”这行代码将Message塞入了一个MessageQueue对象中,我们看看这个方法又做了什么:
frameworks\base\core\java\android\os\MessageQueue.java
final boolean enqueueMessage(Message msg, long when) { …… synchronized (this) { …… msg.when = when; //Log.d("MessageQueue", "Enqueing: " + msg); Message p = mMessages; if (p == null || when == 0 || when < p.when) { msg.next = p; mMessages = msg; needWake = mBlocked; // new head, might need to wake up } else { Message prev = null; while (p != null && p.when <= when) { prev = p; p = p.next; } msg.next = prev.next; prev.next = msg; needWake = false; // still waiting on head, no need to wake up } } …… return true; } |
以上代码只做了一件事,将我们的Message加入到MessageQueue中,并根据when这个时间值对我们的MessageQueue中的Message进行了排序。
这个when值,就是之前我们传进来的那个uptimeMillis。
那么,消息被放到了我们的MessageQueue中,又由谁来取出并分发呢?
答案是我们的Looper。
我们的应用程序启动,主线程开启时,系统会创建一个Looper,并调用其loop方法,使其开始轮询MessageQueue中的消息:
frameworks\base\core\java\android\app\ActivityThread.java
public static final void main(String[] args) { …… Looper.prepareMainLooper(); …… Looper.loop(); …… }
|
frameworks\base\core\java\android\os\Looper.java
public static final void prepareMainLooper() { prepare(); setMainLooper(myLooper()); …… } …… public static final void prepare() { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper()); } …… public static final Looper myLooper() { return (Looper)sThreadLocal.get(); } …… public static final void loop() { Looper me = myLooper(); MessageQueue queue = me.mQueue; while (true) { Message msg = queue.next(); // might block if (msg != null) { if (msg.target == null) { return; } …… msg.target.dispatchMessage(msg); …… } } } |
Loop方法实际上是维持着一个死循环,他不停的从MessageQueue中取到Message并将Message分发。
当MessageQueue中没有消息时,Loop会处于阻塞状态:
Message msg = queue.next(); // might block |
Message被分发的代码为:
msg.target.dispatchMessage(msg); |
这里的msg.target,即发送我们这个Message的Handler对象,因此,这行代码还是调用回了我们的Handler的dispatchMessage方法:
frameworks\base\core\java\android\os\Handler.java
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } } |
由代码可知,我们通过Handler发送的消息,最终由我们Handler的handleMessage方法来进行处理,Handler的这一套运行机制到此完毕。
好了,整个运行机制我们走通了,那么我们再来想一个问题:
Handler机制靠什么保证消息不混乱
假如现在我们new了10几个Handler,同时去sendMessage,我们如何保证哪个Handler发送的消息,就交由哪个Handler的handleMessage方法去处理?
牢记我们发送消息和分发消息的时候的这2行代码:
frameworks\base\core\java\android\os\Handler.java
public boolean sendMessageAtTime(Message msg, long uptimeMillis) { boolean sent = false; MessageQueue queue = mQueue; if (queue != null) { msg.target = this; sent = queue.enqueueMessage(msg, uptimeMillis); } …… return sent; } |
frameworks\base\core\java\android\os\Looper.java
public static final void loop() { Looper me = myLooper(); MessageQueue queue = me.mQueue; while (true) { Message msg = queue.next(); // might block if (msg != null) { if (msg.target == null) { return; } …… msg.target.dispatchMessage(msg); …… } } } |
通过这个“msg.target”,我们就可以保证:哪个Handler发送的消息,哪个Handler来处理。Google这么设计是不是什么巧妙?
相信细心的朋友 在源码中看到这么一个变量 : sThreadLocal,他其实是一个ThreadLocal类型的变量,那么ThreadLocal又是个什么东西呢? 我们来说一说:
ThreadLocal
ThreadLocal就是线程局部变量,经常使用此方法保存线程内的共享变量。
同一个线程内的多个不同的类,可以通过ThreadLocal来共享全局变量。
当线程结束后,对应该线程的局部变量将自动被垃圾回收,所以显式调用该方法清除线程的局部变量并不是必须的操作。
所有在主线程new出来的Handler,最后都是通过ThreadLocal取用主线程创建的那个Looper,来实现的消息分发。
Handler机制中,我们通过ThreadLocal来保证一个线程中只有一个Looper。
好了,我们最后再来解决一个问题,上面源码中我说过Looper内部维护这一个死循环,那么一定有人有疑问,Looper不会阻塞主线程吗?
我们来揭晓答案吧:
Looper是不会阻塞主线程的,正因为有Looper这个死循环,我们的app才能去即时的相应用户的操作。
不止是我们自己通过代码逻辑发送的Message,包括我们应用中所有的操作,比如开启一个Activity,调用Activity生命周期的方法:onCreate\onResume等,都是通过Handler发送消息,由Looper轮训到来处理的。
因此,Looper不会阻塞我们的主线程。
好了,Handler机制,以及一些常见问题我们一起学习完了,对于一些有经验的开发者理解起来还是很easy的。当然也欢迎大家多提意见。
Now is the funture!