Handler
一、成员与构造函数
Handler有一个静态成员值得注意:
private static Handler MAIN_THREAD_HANDLER = null;
不出所料,有一个方法与其搭配:
public static Handler getMain() {
if (MAIN_THREAD_HANDLER == null) {
MAIN_THREAD_HANDLER = new Handler(Looper.getMainLooper());
}
return MAIN_THREAD_HANDLER;
}
这里直接将其Looper设置为了MainLooper
构造函数
Handler的构造函数之间有回调关系,最终都会分别调用两种构造函数:
public Handler(Callback callback, boolean async) {
........
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
所以如果Looper对象不传递的话,Handler会自己调用Looper.muLooper()获取Handler所在线程绑定的Looper对象。
二、Message的分发
Handler通过dispatchMessage分发Message:
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
private static void handleCallback(Message message) {
message.callback.run();
}
可见,处理Message的优先级为:
- Handler的handleCallback优先级最高
- Handler的Callback回调第二优先级
- Handler的handleMessage方法优先级最低
三、Message的产生
Handler本身有很多生成Message的方法:
public final Message obtainMessage()
{
return Message.obtain(this);
}
public final Message obtainMessage(int what)
{
return Message.obtain(this, what);
}
public final Message obtainMessage(int what, Object obj)
{
return Message.obtain(this, what, obj);
}
public final Message obtainMessage(int what, int arg1, int arg2)
{
return Message.obtain(this, what, arg1, arg2);
}
public final Message obtainMessage(int what, int arg1, int arg2, Object obj)
{
return Message.obtain(this, what, arg1, arg2, obj);
}
平时都说,推荐使用Message.obtain()和Handler对象的obtainMessage方法来创建Message对象,且二者等价,原因就在于handler对象的obtainMessage方法都是调用的Message.obtain()系列
注意:在Message.obtain方法中会将其target属性初始化为Handler本身
四、Message消息的发送
Handler中有很多方法可以发送消息,主要分为两种:post和send
1. Post系列方法
这种方法都是直接post一个Runnable对象,所以首先来看看如何将一个Runnable对象封装成一个Message:
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
private static Message getPostMessage(Runnable r, Object token) {
Message m = Message.obtain();
m.obj = token;
m.callback = r;
return m;
}
很简单,就直接创建一个Message对象,然后将Runnable设置为Message的callback属性
Q:post生成的Message没有将handler对象绑定到其target属性中?
对于该情况下的target赋值发生在handler的enqueueMessage方法中
现在我们来看post系列的方法:
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
public final boolean postAtTime(Runnable r, long uptimeMillis)
{
return sendMessageAtTime(getPostMessage(r), uptimeMillis);
}
public final boolean postAtTime(Runnable r, Object token, long uptimeMillis)
{
return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
}
public final boolean postDelayed(Runnable r, long delayMillis)
{
return sendMessageDelayed(getPostMessage(r), delayMillis);
}
public final boolean postDelayed(Runnable r, Object token, long delayMillis)
{
return sendMessageDelayed(getPostMessage(r, token), delayMillis);
}
public final boolean postAtFrontOfQueue(Runnable r)
{
return sendMessageAtFrontOfQueue(getPostMessage(r));
}
可以看到,Post方法都是回调的sendMessage系列方法
2. send系列方法
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
public final boolean sendEmptyMessage(int what)
{
return sendEmptyMessageDelayed(what, 0);
}
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}
public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageAtTime(msg, uptimeMillis);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
可见,大部分send方法都是调用的sendMessageDelayed方法,而sendMessageDelayed方法又是调用的sendMessageAtTime方法实现的,所以我们可以说,Handler中所有发送Message的方法的实现都是sendMessageAtTime:
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
而sendMessageAtTime的实现实际上就是回调了enqueueMessage:
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
最终我们搞清楚了,原来Handler中所有的回调,都最终归于queue.enqueueMessage方法。
而Handler中还有一个比较奇葩的方法:
public final boolean sendMessageAtFrontOfQueue(Message msg) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, 0);
}
这个看起来和sendMessageXX没啥不同啊,仔细发现,sendMessageDelayed在回调sendMessageAtTime的时候第二个参数做了手脚:
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis)
其在delayMillis基础上加了SystemClock.uptimeMillis(这个意义是手机从开机到当下的时间间隔),所以其永远都是一个大于0的数;而sendMessageAtFrontOfQueue则把第二个参数直接置为0,实际上其效果等同于:sendMessageAtTime(msg, 0)
注意:1. MessageQueue在执行enqueue的时候会根据这个msg.when进行插入,所以该值越小越先被MessageQueue.next方法返回,从而越先被Handler处理。 2. 为什么选择使用SystemClock.uptimeMillis而不是System.currentMillis是因为当我们手动更改系统时间的时候会影响后者的值,导致MessageQueue在入队插入的时候逻辑混乱
3. 小结
粗略下来,感觉post和send实现都一样,为啥要有两种api发送Message,虽然实现机制都一样,但是在处理的时候就不一样了。还记得handler的dispatchMessage中处理消息的优先级吗?没错:post系列方法的getPostMessage中将post的参数Runnable赋值给了Message的callback,所以导致在处理Post的消息的时候是通过最高优先级的handleCallback方法处理的;而send系列方法,在通常情况下是通过handler的callback属性或者handleMessage方法处理消息。
五、经典面试题
Q1:子线程中创建Handler中报错是为什么?
在Handler的构造器中有这么一段:
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
因为没有执行Looper.prepare()导致Looper.mylooper返回为null
Q2:如何在子线程创建Looper?
Looper.prepare()
Q3:为什么能通过Handler实现线程切换?
纯属个人理解:Handler的MessageQueue来自于Looper中的MessageQueue,而在Message.obtain中,Message的target被赋值为了Handler对象;Looper在从MessageQueue中取出Message后通过message.target来处理消息,所以消息的处理是在Looper所绑定的线程,而Handler可以在任意线程往MessageQueue中发送消息,所以实现了线程的切换
Q4:Handler处理消息发送在那个线程,是Handler所在的线程还是Looper?
Looper所在的线程
Q5:Looper和Handler一定要处于一个线程吗?子线程中可以用MainLooper去创建Handler吗?
不一定位于一个线程;子线程可以通过MainLooper创建Handler:实现有两种:
Handler h = new MyHandler(Looper.getMainLooper());
Handler h = Handler.getMain(); // Handler的api
Q6:Handler的post/send()的原理
最终都是调用的sendMessageAtTime -> enqueueMessage -> mQueue.enqueue
Q7:Handler的dispatchMessage()分发消息的处理流程?
优先级为:
- 如果msg.callback不为空,调用handleCallback
- 如果mCallback属性不为空,则调用mCallback.handleMessage
- 最后调用handleMessage方法
Q8:Handler为什么要提供Callback构造方法?
正常使用Handler要使用一个子类继承Handler,然后再子类中实现handleMessage方法,而使用Callback构造函数则可以简化这一流程,一步到位。
Looper
一、成员和构造器
Looper的成员有三个需要关注:
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static Looper sMainLooper; // guarded by Looper.class
final Thread mThread;
其中的sThreadLocal就是实现Looper和线程绑定的原因。
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
构造器中直接初始化了mThread和mQueue
二、prepare()、myLooper()方法
该方法大家都比较熟悉:
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
就是在当前线程中初始化了Looper对象,并且把它保存到了ThreadLocal中
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
myLooper()方法就是将Looper对象从ThreadLocal中取出来
三、quit和quitSafely
二者的区别就在于:mQueue.quit参数是否为true
public void quit() {
mQueue.quit(false);
}
public void quitSafely() {
mQueue.quit(true);
}
通过注释我们知道第一个方法可能导致还有没有接受到的Message,可能会产生意外情况,所以推荐我们使用第二个方法
四、loop方法
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
....
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
...
try {
msg.target.dispatchMessage(msg);
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
...
msg.recycleUnchecked();
}
}
这里只保留了关键的代码:
- 要想loop结束只有msg为null,而在MessageQueue中只有调用了quit方法才会导致其next方法返回null;而Looper的quit和quirSafely方法内部就是回调了mQueue的quit方法,所以只有调用Looper的quit或者quitSafely方法才会终止loop()方法
- msg.target.dispatchMessage(msg)中,msg的target即为handler对象,所以这里就实现了跨线程
五、经典面试题
Q1:如何开启消息循环?
Looper.loop()
Q2:Looper两个退出方法有何区别?
quit会导致还未接收到的Message无法处理
quitSafely不会
Q3:如何终止消息循环?
quitSafely
Q4:Looper的loop流程
- 获取Looper和MessageQueue
- 无限for循环取出msg
- 执行msg.target.dispatchMessage
Q5:MessageQueue的next什么情况下返回null
执行了quit或者quitSafely
Q6:Android如何保证一个线程最多只能有一个Looper?
通过ThreadLocal保证只有一个Looper
MessageQueue
这里需要提一下其Message mMessages代表链表的表头
我们这里只讨论其enqueueMessage方法和next方法。
1. enqueueMessage方法
boolean enqueueMessage(Message msg, long when) {
。。。
synchronized (this) {
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
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;
}
is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
可以发现,这里就是按照when的大小,将Message插入到链表中
2. next方法
Message next() {
...
int nextPollTimeoutMillis = 0;
for (;;) {
...
//根据我们上面的分析,nextPollTimeMillis为0则不阻塞,也就是第一次循环不阻塞
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
//这里判断msg不为空但是target为空,而我们enqueueMessage的时候特意设置了target的
//所以这里的msg不是我们设置而是系统在初始化的时候设置的屏障,这里不再详解
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
//这里是正常情况下的msg
if (msg != null) {
//未达到处理时间的,将会计算需要等待的时间,不超过整形的最大值
if (now < msg.when) {
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
//可以处理的则直接取出后返回
} else {
// Got a message.
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();
return msg;
}
//这里是队列中没有消息
} else {
nextPollTimeoutMillis = -1;
}
//上面分别对消息队列进行判断然后修改nextPollTimeoutMillis,而之前的分析可以看出这个值就是线程
//需要阻塞的时长,有未达到处理时间的消息则阻塞对应时间,没有消息则一直阻塞直到被唤醒
...
}
...
}
}
next方法详细分析:MessageQueue的next方法详解