Handler的用法网上有很多,这里主要分析其实现机制。
Handler相关的几个重要概念:Handler,Looper,Message,MessageQueue
Handler:用于线程间通信,与Looper关联,它负责向一个线程的消息队列里加入消息,或者接收Looper发送的消息并处理。
Message:消息,可以包含任意对象。
MessageQueue:消息队列,存放Message对象。
Looper:与一个Handler和一个线程关联,用于从线程的MessageQueue中循环获取Message并发送给Handler
=======================
回顾下Handler的简单用法:主线程中创建一个Handler,然后子线程调用其sendMessage方法发送消息,再从其handleMessage方法中接收消息。
handler = new Handler() {
@Override
public void handleMessage(Message msg) {
textView.setText("11111111");
}
};
send.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread(new Runnable() {
@Override
public void run() {
Message msg = Message.obtain();
msg.what = 1;
handler.sendMessage(msg);
}
}).start();
}
});
先从Handler的构造方法开始分析:
public Handler() {
this(null, false);
}
public Handler(Callback callback, boolean async) {
...
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
mLooper = Looper.myLooper();
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
sThreadLocal是一个ThreadLocal的全局变量:
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
所以Looper.myLooper()返回的是当前线程关联的Looper对象。注意下面的if语句,如果mLooper对象为空,则抛出异常。对于主线程也就是UI线程来说,它在启动时就会和一个Looper是关联,所以不会返回null。主线程的启动流程:
先需要了解一个类ActivityThread:
/**
* This manages the execution of the main thread in an
* application process, scheduling and executing activities,
* broadcasts, and other operations on it as the activity
* manager requests.
*
* {@hide}
*/
这个类管理一个App主线程也就是我们所说的UI线程,它负责Activity的启动。
ActivityThread的入口函数main:
public static void main(String[] args) {
...
Looper.prepareMainLooper();
...
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
这里看到调用了Looper的静态方法prepareMainLooper,
Looper.prepareMainLooper():
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
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.prepare方法中创建了一个Looper对象,并且保存到Looper的sThreadLocal这个ThreadLocal变量中。
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
Looper内部创建了一个MessageQueue对象赋值给mQueue对象,并且将当前线程赋值给mThread。
接下来看Handler构造方法的下一行代码:
mQueue = mLooper.mQueue;
将Looper内部的MessageQueue对象赋值给全局变量mQueue
当我们需要用Handler发送消息时,会调用sendMessage系列方法,其中sendMessage方法的实现是:
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) {
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);
}
可以看到内部调用了 enqueueMessage,并且将当前线程关联的MesssageQueque对象和发送的Message对象作为参数传入,那么看下 enqueueMessage:
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
msg.target = this;
这行将当前Handler赋值给Message的target变量。这个target变量作用是记录需要被回调handleMessage的Handler,接下来在MessageQueue的源码中会看到实现。
enqueueMessage:
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 p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
// Inserted within the middle of the queue. Usually we don't have to wake
// up the event queue unless there is a barrier at the head of the queue
// and the message is the earliest asynchronous message in the queue.
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;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
同步块里的语句作用是把Message对象放入MessageQueue中,通过Message.next来指定位置顺序。
通过阅读以上一系列代码,得出结论:
创建Handler时,Handler对象会和当前线程的Looper对象关联,Looper内部包含一个MessageQueue,Handler也引用了这个MessageQueue,Handler通过sendMessage方法发送的Message对象会插入这个MessageQueue当中。
接下来,当Handler在主线程中发送消息后,其handlerMessage方法如何被回调呢?答案就在Looper.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;
}
...
msg.target.dispatchMessage(msg);
...
}
}
首先通过myLooper获取当前线程关联的Looper,然后再获取Looper中的MessageQueue对象,for循环语句块是一个死循环,当MessageQueue中没有Message对象时会阻塞,一旦获取Message对象,会调用这个Message的target的dispatchMessage方法,target变量就是发送这个Message的Handler对象,target是在Handler的enqueueMessage方法中指定的。
可以在ActivityThread的main方法中看到,Looper.loop在最后被调用,所以对于主线程的Looper,会一直从MessageQueue中获取消息。
接下来看dispatchMessage: public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
如果handler没有设置callback的话,那么调用它的handleMessage方法。
通过阅读以上loop和dispatchMessage的代码,得出结论:Looper会一直从MessageQueue中取消息,并且调用当前消息关联的Handler的dispatchMessage。
以上代码分析是建立在主线程中创建Handler的情况上的,如果在子线程创建一个Handler,由于子线程没有创建Looper,所以在构造方法中调用Looper.myLooper()会返回null, mLooper对象为空,会抛出运行时异常:
new Thread(new Runnable() {
@Override
public void run() {
handler = new Handler();
Message msg = Message.obtain();
msg.what = 1;
handler.sendMessage(msg);
}
}).start();
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
at android.os.Handler.<init>(Handler.java:200)
at android.os.Handler.<init>(Handler.java:114)
at ohehehou.libtest.MainActivity$1$1.run(MainActivity.java:38)
at java.lang.Thread.run(Thread.java:818)
所以,如果要在子线程中创建Handler并且向主线程发送消息,可以手动调用Looper.prepare来创建一个和子线程关联的Looper对象,并且还需要调用Looper.loop,这样Looper才能循环获取消息。
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
handler = new Handler();
Message msg = Message.obtain();
msg.what = 1;
handler.sendMessage(msg);
Looper.loop();
}
}).start();