1. 创建Handler对象需要Looper:
在主线程中可以直接创建Handler对象,而在子线程中需要先调用Looper.prepare()才能创建Handler对象。
看源码:Handler的无参构造函数中有这样一个判断:
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
显然,构造Handler对象,必须保证所在线程中存在一个Looper对象,同时依靠looper得到MessageQueue对象。
在主线程中,本身就含有Looper对象,因为在程序启动的时候,已经自动调用了Looper.prepare()方法。
public static final void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}
Looper的prepare方法的作用就是判断sThreadLocal中是否已经存在Looper了,如果还没有则创建一个新的Looper设置进去。
2. Looper的作用:
Looper类用来为一个线程开启一个消息循环。
默认情况下android中新诞生的线程是没有开启消息循环的。(主线程除外,主线程系统会自动为其创建Looper对象,并开启消息循环
Looper.loop()
)
Looper对象通过MessageQueue来存放消息和事件。一个线程只能有一个Looper,MessageQueue是在Looper的构造函数中创建的,因此一个Looper对应一个MessageQueue。通常是通过Handler对象来与Looper进行交互的。Handler向指定的Looper发送消息。
默认情况下Handler会与其被定义时所在线程的Looper绑定,比如,Handler在主线程中定义,那么它是与主线程的Looper绑定。
new Handler()
等价于new Handler(Looper.myLooper()
)。Looper.myLooper()
: 用户获取当前进程的looper对象。
Looper.getMainLooper()
: 用于获取主线程的Looper对象。
Looper.loop()
: 让Looper开始工作,从消息队列里取消息,处理消息。
注意:写在
Looper.loop()
之后的代码不会被执行,这个函数内部是一个死循环,当调用mHandler.getLooper().quit()
后,loop才会中止,其后的代码才能得以运行。
3. 线程间发消息:
不论Handler对象在哪个线程中发出消息,最终消息都会回到创建Handler对象的那个线程中取处理。
4. 消息传递机制
Hnadler从sendMessge到handleMessage的过程。
Handler调用自身的sendMessageAtTime(Message msg, long uptimeMillis)方法,msg被放入MessageQueue对象中去。
MessageQueue调用其自身的enqueMessage()方法,将所有放入的Message对象按时间排序。方法内部主要过程有:msg.when表示该条Messge的入队时间,msg.next表示下一条准备出队的Message。
-
Looper调用自身的loop()方法,依次将MessageQueue中的Message取出。MessageQueue的next()方法,就是消息队列的出队方法。
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.recycle();
}
}
-
每当有一个消息出队,就将它传递到
msg.target
(就是发这条Message的Handler)的dispatchMessage()
方法中。如果mCallback不为空,则调用mCallback的handleMessage()
方法,否则直接调用Handler的handleMessage()
方法,并将消息对象作为参数传递过去。public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg); // 回到handler自身的handleMessage方法
}
5. 最终由谁处理消息?
在Looper的loop()方法中,取出从MessageQueue中取出下一位Message之后,就进入了处理消息阶段。
public static final void loop() {
Looper me = myLooper();
MessageQueue queue = me.mQueue;
while (true) {
Message msg = queue.next();
if (msg != null) {
if (msg.target == null) {
return;
}
msg.target.dispatchMessage(msg);
msg.recycle();
}
}
}
msg.target
是谁?
回到最开始的Handler的sendMessage方法:
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");
}
return sent;
}
再来看看Message
类的属性:
public final class Message implements Parcelable {
public int what;
public int arg1;
public int arg2;
public Object obj;
int flags;
long when;
Bundle data;
Handler target; // target处理
Runnable callback; // Runnable类型的callback
// sometimes we store linked lists of these things
Message next; // 下一条消息,消息队列是链式存储的
// 代码省略 ....
}
所以,msg.target
就是发送这条msg的Handler对象。
这就是“不论Handler对象在哪个线程中发出消息,最终消息都会回到创建Handler
对象的那个线程中取处理。”的原理。饶了一圈,最终处理消息的还是这条Message
的Handler
对象,然后调用自身的dispatchMessage(msg)
方法,消息对象作为这个其参数。
6. 处理消息的方式有几种?
深入看一下消息的最终处理方式:Handler的dispatchMessage(msg)方法。
public void handleMessage(Message msg) {
}
private final void handleCallback(Message message) {
message.callback.run();
}
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg); // 设置了callback,调用callback(Runnable)的run方法
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg); // 没有设置callback,直接调用handleMessage
}
}
从Message
类的属性中可知,msg.callback
指的是一个Runnable
对象。
Handler
分发消息有两种情况,一种情况是直接sendMessage
,这种情况不会设置callback。另一种情况是诸如post(Runnable r)
,postDelayed(Runnable r, long l)
等方法,这种情况会设置callback。
public final boolean post(Runnable r) {
return sendMessageDelayed(getPostMessage(r), 0);
}
private final Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
public final boolean sendMessageDelayed(Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
post()的使用场景举例:
Handler handler = new Handler();
new Thread(new Runnable() {
@Override
public void run() {
handler.post(new Runnable() {
@Override
public void run() {
}
});
}
}).start();
另外,View的post()
方法, Activity的runOnUiThread()
方法,均是对Handler的post()
方法进行了包装。
7. 总结:Handler、Looper、MessageQueue分别存在于哪里,如何相互工作?
Handler的创建必须保证其所在线程有且只有一个Looper对象的存在。Looper构造的时候,MessageQueue会随之一同创建。一个线程中可以有多个Handler的存在,但与之对应的线程、Looper和MessageQueue只有一个。
随后,Handler对象不论在哪个线程中发Message,都会被与之对应的MessageQueue存放到自身队列当中去。并且根据所发送的Message的target属性,标记发送这条Message从属于哪个Handler。
随后,通过Looper和MessageQueue的按时间先后依次取出Message后,再根据Message的target属性,识别这条Message是哪个Handler发送的,交由这个Handle回到创建时候的线程中去处理这个Message。
8. 引申类:HandlerThread
-
构造:
HandlerThread继承于Thread,所以它本质就是个Thread。与普通Thread的差别就在于,它在执行run()方法的时候,会自动创建Looper对象,并持有其作为自己的一个成员变量。@Override public void run() { mTid = Process.myTid(); Looper.prepare(); synchronized (this) { mLooper = Looper.myLooper(); notifyAll(); } Process.setThreadPriority(mPriority); onLooperPrepared(); Looper.loop(); mTid = -1; }
用途:
Handler最终处理消息所在的线程是一开始创建这个Handler的所在的线程。假如这个处理消息过程是一个耗时的过程,那么放在主线程中是不合适的。HandlerThread的作用是让耗时工作在这个线程中处理。-
用法:
private HandlerThread handlerThread; private Handler handler; @Override public void onCreate() { super.onCreate(); handlerThread = new HandlerThread("test"); handlerThread.start(); handler = new Handler(handlerThread.getLooper()) { @Override public void handleMessage(Message msg) { super.handleMessage(msg); // 耗时操作,代码省略 .... handler1.sendEmptyMessageDelayed(0x01, updateTime1); } }; handler.sendEmptyMessage(0x01); } @Override public void onDestroy() { super.onDestroy(); handlerThread.quit(); }