大家都知道,Android不允许在子线程更新UI,所有的UI操作都在主线程完成,当我们在子线程处理完一些逻辑后需要更新UI怎么做呢,大家都知道可以通过Handler来实现。我们来看一下示例代码:
private Handler mHandler = new Handler() {
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
switch (msg.what) {
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new Thread() {
@Override
public void run() {
super.run();
try {
Thread.sleep(2000);
Message msg = Message.obtain();
msg.what = 1;
mHandler.sendMessage(msg);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
那么为什么在子线程通过调用mHandler.sendMessage(msg)后,就可以在mHandler.handleMessage()里面更新UI了呢,这就是我们今天要搞清楚的问题。
首先,我们来看一下源码里面对Handler的介绍
/**
* A Handler allows you to send and process {@link Message} and Runnable
* objects associated with a thread's {@link MessageQueue}. Each Handler
* instance is associated with a single thread and that thread's message
* queue. When you create a new Handler, it is bound to the thread /
* message queue of the thread that is creating it -- from that point on,
* it will deliver messages and runnables to that message queue and execute
* them as they come out of the message queue.
*
* <p>There are two main uses for a Handler: (1) to schedule messages and
* runnables to be executed as some point in the future; and (2) to enqueue
* an action to be performed on a different thread than your own.
*
* <p>Scheduling messages is accomplished with the
* {@link #post}, {@link #postAtTime(Runnable, long)},
* {@link #postDelayed}, {@link #sendEmptyMessage},
* {@link #sendMessage}, {@link #sendMessageAtTime}, and
* {@link #sendMessageDelayed} methods. The <em>post</em> versions allow
* you to enqueue Runnable objects to be called by the message queue when
* they are received; the <em>sendMessage</em> versions allow you to enqueue
* a {@link Message} object containing a bundle of data that will be
* processed by the Handler's {@link #handleMessage} method (requiring that
* you implement a subclass of Handler).
*
* <p>When posting or sending to a Handler, you can either
* allow the item to be processed as soon as the message queue is ready
* to do so, or specify a delay before it gets processed or absolute time for
* it to be processed. The latter two allow you to implement timeouts,
* ticks, and other timing-based behavior.
*
* <p>When a
* process is created for your application, its main thread is dedicated to
* running a message queue that takes care of managing the top-level
* application objects (activities, broadcast receivers, etc) and any windows
* they create. You can create your own threads, and communicate back with
* the main application thread through a Handler. This is done by calling
* the same <em>post</em> or <em>sendMessage</em> methods as before, but from
* your new thread. The given Runnable or Message will then be scheduled
* in the Handler's message queue and processed when appropriate.
*/
从上面的注释,我们可以看到,Handler主要有2个作用,1是调度和处理Message,2是在别的Thread去处理Message,还有就是,Handler是跟Thread以及Thread's MessageQueue绑定的。我们先来看看Handler的构造方法(为了阅读方便,对源码做了一些删减,下同)
public Handler(Callback callback, boolean async) {
mLooper = Looper.myLooper();//1.绑定Looper
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;//2.绑定Looper.mQueue
}
从Handler的构造方法,我们可以看出,Handler是与Looper以及Looper.mQueue绑定的,而之前源码注释说的是Handler与Thread以及Thread's MessageQueue绑定,那么我们不难想到Looper是与Thread绑定的,那么我们就看看mLooper = Looper.myLooper()的具体实现
public final class Looper {
/*
* API Implementation Note:
*
* This class contains the code required to set up and manage an event loop
* based on MessageQueue. APIs that affect the state of the queue should be
* defined on MessageQueue or Handler rather than on Looper itself. For example,
* idle handlers and sync barriers are defined on the queue whereas preparing the
* thread, looping, and quitting are defined on the looper.
*/
// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();//static final sThreadLocal
private static Looper sMainLooper; // guarded by Looper.class
final MessageQueue mQueue;//2.1在Handler构造方法里面调用的mQueue = Looper.mQueue
final Thread mThread;
private Looper(boolean quitAllowed) {//构造方法私有
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
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构造方法的地方
}
public static @Nullable Looper myLooper() {
return sThreadLocal.get();//1.1在Handler构造方法里面调用的mLooper = Looper.myLooper
}
}
我们可以看到,Looper.myLooper()是调用了Looper的static final 成员ThreadLocal<Looper> sThreadLocal里面的get方法,并且Looper的构造方法是私有的,而且构造方法只在Looper.prepare()方法里面有调用,而调用的地方正是构造了一个Looper并且放在了sThreadLocal里面,所以,所有要用到Looper的地方都是通过静态对象sThreadLocal.get()获得的。我们来看看sThreadLocal.get()的实现
public T get() {
Thread t = Thread.currentThread();//获取当前Thread
ThreadLocalMap map = getMap(t);//利用currentThread获取ThreadLocalMap
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);//利用当前ThreadLocal从Map里获取Entry,Entry的key是ThreadLocal,value是Looper
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
由此我们可以看到,Looper其实是与Thread绑定的,获取到currentThread后又紧接着获取了currentThread.threadLocals,然后从这个Thread.threadLocals(ThreadLocalMap对象)里面去通过ThreadLocal获取Looper,而Handler又是与Looper绑定的,所以最终Handler也是与Thread绑定了,这就验证了Handler注释里面所说的Handler与Thread绑定,那么Handler与Thread's MessageQueue又是如何绑定的呢,其实我们上面贴的Handler的构造方法里面有一行代码mQueue = mLooper.mQueue,我们来看看Looper.mQueue,回到上面Looper的代码,就可以看到mQueue的初始化是在Looper构造方法里面初始化的。
那么在子线程用主线程创建的Handler去sendMessage为什么这个消息就能到主线程了呢。我们一起来看看代码(代码有精简,方便阅读)
//1
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
//2
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
//3
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
return enqueueMessage(queue, msg, uptimeMillis);
}
//4
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;//Message.target = this (Handler与Message绑定)
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);//Handler.sendMesage后Message被放进了与Handler绑定的Looper.mQueue中
}
消息放进去了,怎么取消息呢,什么时候执行呢,我们来看一下源码里面对Looper的注释
/**
* Class used to run a message loop for a thread. Threads by default do
* not have a message loop associated with them; to create one, call
* {@link #prepare} in the thread that is to run the loop, and then
* {@link #loop} to have it process messages until the loop is stopped.
*
* <p>Most interaction with a message loop is through the
* {@link Handler} class.
*
* <p>This is a typical example of the implementation of a Looper thread,
* using the separation of {@link #prepare} and {@link #loop} to create an
* initial Handler to communicate with the Looper.
*
* <pre>
* class LooperThread extends Thread {
* public Handler mHandler;
*
* public void run() {
* Looper.prepare();
*
* mHandler = new Handler() {
* public void handleMessage(Message msg) {
* // process incoming messages here
* }
* };
*
* Looper.loop();
* }
* }</pre>
*/
public final class Looper {
}
子线程创建Handler并使用,需要先调用Looper.prepare()然后再调用Looper.loop(),Looper.prepare()做的工作其实就是创建一个Looper,然后将Looper放进当前线程的ThreadLocalMap里面,我们可以看一下精简过后的代码
//1
private static void prepare(boolean quitAllowed) {
sThreadLocal.set(new Looper(quitAllowed));
}
//2
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
//3
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
我们再来看看Looper.loop()的源码
public static void loop() {
final Looper me = myLooper();
final MessageQueue queue = me.mQueue;
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
// Allow overriding a threshold with a system prop. e.g.
// adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
final int thresholdOverride =
SystemProperties.getInt("log.looper."
+ Process.myUid() + "."
+ Thread.currentThread().getName()
+ ".slow", 0);
boolean slowDeliveryDetected = false;
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
final long dispatchEnd;
try {
msg.target.dispatchMessage(msg);
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
if (logSlowDelivery) {
if (slowDeliveryDetected) {
if ((dispatchStart - msg.when) <= 10) {
Slog.w(TAG, "Drained");
slowDeliveryDetected = false;
}
} else {
if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
msg)) {
// Once we write a slow delivery log, suppress until the queue drains.
slowDeliveryDetected = true;
}
}
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
msg.recycleUnchecked();
}
}
可以看到Looper.loop()里面开了一个for(;;)死循环去不停的轮询消息,取到消息后就调用msg.target.dispatchMessage(msg)里,也就是Handler.dispatchMessage(Meesage msg),我们看一下源码
public void dispatchMessage(Message msg) {
if (msg.callback != null) {//如果构建Message的时候传入了callback,就调用callback.run() callback是一个Runnable
handleCallback(msg);
} else {
if (mCallback != null) {//如果构建Handler的时候传入了一个mCallback,那么就调用callback.handleMessage(msg),返回true表示消息已被处理
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);//Handler默认的处理方法
}
}
至此,Handler如何与Looper Thread绑定,消息如何发送,如何分发处理就分析完了