Read the fucking source code!
还是源码精妙
当我们面试的时候,经常遇到这样一题,请描述一下Handler的工作方式
然后我们会说,Handler机制包括Handler,Message,MessageQueue,Looper。
Handler会发送Message给MessageQueue,Looper会不断的从Message中取出一个Message,然后调用Handler的handleMessage方法。
当然,还可以说的更详细一点,不过最近感觉,只是了解了使用方法不行,了解了工作机制还是不行,要深入的了解源码,才能感觉到一个优秀的操作系统的伟大之处。
首先我们说一下这几个的数量关系:
一个线程有一个Looper,一个Looper内部有一个MessageQueue,一个MessageQueue有多个Message,并且一个MessageQueue可能有多个Handler的引用,一个Message只对应一个Handler
关于Looper
主线程的Looper
我们都知道一个线程有一个Looper,那么这个怎么实现的呢,我们看源码。
Looper.java
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static Looper sMainLooper; // guarded by Looper.class
final MessageQueue mQueue;
final Thread mThread;
首先看第一行 有一个ThreadLocal变量,一个线程维护一个ThreadLocal副本,互不干扰,这点大家应该都清楚。因为这个sThreadLocal是static final的,所以我们在任何线程都能拿到这个变量。
第二行有个变量sMainLooper,唯一标识UI线程的Looper,这个Looper怎么实例化的呢,在我们的Application入口处:
Looper.prepareMainLooper();
if (sMainThreadHandler == null) {
sMainThreadHandler = new Handler();
}
ActivityThread thread = new ActivityThread();
thread.attach(false);
Looper.loop();
我们看到了在这里的“ Looper.prepareMainLooper()”
我们看一下这个方法都干了什么:
Looper.java
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
第一行“prepare”,我们应该有印象,在子线程里构造Looper,我们会用到Looper.prepare(),其实prepare()方法内部就是调用了这个方法:
Looper.java
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了,就抛出异常
我们看到当传入参数为false的时候,就会执行Looper(quitAllowed)这个构造方法,我们来看一下这个构造方法:
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
这一段揭示了Looper和MessageQueue和Thread的关系:Thread有一个Looper,一个Looper有一个MessageQueue!
在这个构造方法中就实例化了一个MessageQueue,这个就是主线程的MessageQueue,mThread就是主线程。
调用构造函数之后,就把一个Looper加入到了sThreadLocal中了。
最后一行调用了myLooper():
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
这个方法就是返回当前的Looper实例。
子线程的Looper
上面我们说,如果子线程想拿到一个Looper要调用Looper.prepare(),这个方法又会调用prepare(true),当参数为true时,我们也调用了Looper()的含参构造方法,至于这个参数什么意思,下面再说。就会把新的looper加入到sThreadLocal中。
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;
// 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();
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
这一部分的代码很长,总的来说,就是开启了一个无限循环,不断的从MessageQueue中拿消息,
如果没有消息,就会退出,上面说 queue.next(); // might block,下面我们再来分析MessageQueue。
小结:怎么在子线程和主线程拿到Looper我们搞清楚了,Looper怎么和MessageQueue对应起来的,下面慢慢说。
MessageQueue
MessageQueue在哪实例化的呢,在这:
Looper.java
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
下面来看MessageQueue的构造方法。
MessageQueue.java
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = nativeInit();
}
这个变量看名字应该是标记MessageQueue是否可以退出。
Message
一个Message只属于一个Handler,这个在下面会说。
其他三个只是处理消息的媒介,这个才是真正的消息内容,我们看Message都有什么实例变量:
public int what;
public int arg1;
public int arg2;
public Object obj;
常用的就是这几个,what和obj我们最常用。
what就是用户自定义的标识Message的标记,在Handler处理的时候,可以根据这个what做具体的工作。
obj是Message携带的唯一一个对象。
实例化一个Message对象的时候,最好的方法是调用Message.obtain();
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
return new Message();
}
spool应该是Message链中的最后一个消息,然后取出这个消息返回,这一段自己没有看太懂,想深入了解的同学可以自己查一下。
小结:Message大致的用法就是这样,比较简单主要是注意要习惯用Message.obtain来获取消息。下面我们来看Handler。
Handler
Handler和Message的关系
一个Message只属于一个Handler,我们看一个Message怎么和一个Handler关联起来的,我们通常发送消息用Handler.sendMessage,我们看这个方法:
Handler.java
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
其实调用了这个方法sendMessageDelayed(msg, 0);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);
}
这一段就是将Handler发送的message送到Handler对应的Looper的MessageQueue中。
我们看一下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,每个Message的Target就是在这设置的。
我们还可以重复利用Message,用这个方法Handler.obtainMessage(int what, Object obj)。
Handler.java
public final Message obtainMessage(int what, Object obj)
{
return Message.obtain(this, what, obj);
}
Handler和MessageQueue的关系
上面我们说发送Message的时候,会将这个Message发送到Handler对应的MessageQueue中,这个MessageQueue怎么来的呢?
我们知道MessageQueue实际上在Looper里,我们看这个Looper怎么得到的:
Handler.java
public Handler() {
this(null, false);
}
Handler的构造方法
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
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;
}
我们看到这个Looper是通过Looper.myLooper()这个方法来的,如果当前线程没有Looper实例,就会抛出异常,所以在子线程实例化Handler的时候,就必须调用Looper.prepare();
当然这也不是唯一的选择,看另一个构造方法:
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
我们可以传入一个Looper,这个Looper通常是主线程的Looper或者是HandlerThread的Looper。