Android中,Handler虽然不是四大组件,但用的次数也不比Activity,Service等四大组件少。虽然大家都知道怎么使用Handler,但是我们不能仅仅停留在使用的层面,对其机制的分析会加深我们对Android的理解。当然了,最终的目的就是在面试的时候碾压面试官,本系列将会对Handler机制做详细的分析。
由于篇幅可能比较长,该系列将分文下面几篇文章:
Handler,MessageQueue,Looper的关系分析
要理清这三者的暧昧关系,我们先分别简单介绍一下它们
Handler
A Handler allows you to send and process Message and Runnable
objects associated with a thread's MessageQueue.
如官网描述的,我们可以用Handler发送并处理Message对象或者一个线程对象,并关联到一个线程的消息队列里,即MessageQueue,而关联的线程就是创建Handler的线程。
Handler使用场景
- 在未来某个时间点上处理Message或者执行Runnable
- 将需要执行的操作通过Handler发送消息在其他线程里执行
Lopper
通常线程默认是不具备循环处理消息的能力的,而Looper就是用来给线程提供循环处理消息能力的类。
当我们需要循环处理消息时,我们在创建Handler的线程里调用Looper.prepare()准备好Looper,之后再调用Looper.loop()开始循环处理消息。
如果我们是在主线程创建的Handler,就不需要做上面的两个操作了,因为主线程已经帮我们处理好了
一个经典的用法如下
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();
}
}
MessageQueue
顾名思义,消息队列。持有Handler发送的消息列表,我们可以使用
Looper.myQueue()来拿到这个对象。
除了上面的三个大头外,还有一个虽然也很重要,但我们不用对他做太多文章,因为它只起到承载信息的作用,也就是我们的Message对象。Handler发送和处理的对象都是它,可能你会说Handler的方法里不一定要使用Message来发送呀,不着急,等等分析源码的时候我们就为什么这么说了
工作原理
当我们创建Handler时,每个Handler实例都会关联一个线程以及这个线程的消息队列,这个线程指的就是创建Handler的线程。
怎么理解呢? 其实很简单,Android里线程无非就是主线程(或UI线程)和子线程,从这点入手,我们就可以理解,如果在主线程创建Handler,会关联到主线程以及主线程里的消息队列, 子线程创建的Handler会关联到子线程以及子线程的消息队列
具体是怎么实现的呢?我们从源码入手看看端倪,
初始化
当我们new Handler()时,会调用到下面这个构造方法,其中 Callback是null,async是false
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;
}
溢出坚持标识FIND_POTENTIAL_LEAKS默认是flase, 故会先执行 Looper.myLooper, 发现就只调用了ThreadLocal的get方法返回一个Looper
public static Looper myLooper() {
return sThreadLocal.get();
}
ThreadLocal里的get实现
/**
* Returns the value of this variable for the current thread. If an entry
* doesn't yet exist for this variable on this thread, this method will
* create an entry, populating the value with the result of
* {@link #initialValue()}.
*
* @return the current value of the variable for the calling thread.
*/
@SuppressWarnings("unchecked")
public T get() {
// Optimized for the fast path.
Thread currentThread = Thread.currentThread();
Values values = values(currentThread);
if (values != null) {
Object[] table = values.table;
int index = hash & values.mask;
if (this.reference == table[index]) {
return (T) table[index + 1];
}
} else {
values = initializeValues(currentThread);
}
return (T) values.getAfterMiss(this);
}
/**
* Gets Values instance for this thread and variable type.
*/
Values values(Thread current) {
return current.localValues;
}
我们看到,获取到当前的线程并取得其ThreadLocal.Values成员变量, 而这个成员变量的初始化的地方也就是在这个get方法里调用initializeValues(currentThread)
/**
* Creates Values instance for this thread and variable type.
*/
Values initializeValues(Thread current) {
return current.localValues = new Values();
}
Value的构造
/**
* Constructs a new, empty instance.
*/
Values() {
initializeTable(INITIAL_SIZE);
this.size = 0;
this.tombstones = 0;
}
private void initializeTable(int capacity) {
this.table = new Object[capacity * 2];
this.mask = table.length - 1;
this.clean = 0;
this.maximumLoad = capacity * 2 / 3; // 2/3
}
ThreadLocal和Value功能就是提供一个Map功能的Object数组来存储数据。
初始化完线程的ThreadLocal.Value后,Looper.myLooper() 最后会调用 ThreadLocal get方法里的 values.getAfterMiss(this)
/**
* Gets value for given ThreadLocal after not finding it in the first
* slot.
*/
Object getAfterMiss(ThreadLocal<?> key) {
Object[] table = this.table;
int index = key.hash & mask;
// If the first slot is empty, the search is over.
if (table[index] == null) {
Object value = key.initialValue();
// If the table is still the same and the slot is still empty...
if (this.table == table && table[index] == null) {
table[index] = key.reference;
table[index + 1] = value;
size++;
cleanUp();
return value;
}
// The table changed during initialValue().
put(key, value);
return value;
}
...
}
因为是第一次初始化,满足条件 table[index] == null,会return key.initialValue(),而
protected T initialValue() {
return null;
}
...
什么鬼,看了这么久return一个null...好吧,那就null吧。
我们回过头来看Handler的初始化,会发现由于mLooper为null会抛出一个RuntimeException
Can't create handler inside thread that has not called Looper.prepare()
所以,我们不得不先调用 Looper.prepare()
/**
* quitAllowed will be 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初始化了一个Looper,这样当我们调用 Looper.myLooper()的时候,其实就是从ThreadLocal里取出在这里初始化的Looper。
好,接着我们看Looper的初始化
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
Looper里创建了一个MessageQueue,并保存当前的线程,也就是我们之前一直提到的 Handler会关联到一个线程。而Handler里的成员变量mQueue也就是Lopper里的mQueue。 到这里初始化就告一段落了
发送消息
初始化完成后,我们就可以通过Handler的postxxx, sendxxx方法来发送消息
我们看sendEmptyMessage方法就可以发现,层层嵌套最终调用的是 sendMessageAtTime 方法
sendEmptyMessage
public final boolean sendEmptyMessage(int what) {
return sendEmptyMessageDelayed(what, 0);
}
sendMessageDelayed
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}
如果是post一个Runnable,它还会调用下面这个方法,将Runnable复制给Message里的callback成员变量,所以说Handler发送和处理的都是Message对象
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
sendMessageDelayed
public final boolean sendMessageDelayed(Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
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);
}
最终呢,就会调用enqueueMessage方法,将Message入栈到Looper里的MessageQueue
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
MessageQueue 队列的实现,原理是使用Message链表,有兴趣的同学可以自己去研究一下,我们就不做过多的阐述。
这样发送消息的过程到这里也基本完结了
处理消息
你还记得吗?当我们在子线程里创建Handler的时候,都会在run方法里调用Looper.loop()方法,异步处理Message对象。如果是在主线程创建的Handler就不是异步了,因为它关联的线程是主线程,Handler的handlerMessage回调是在主线程里执行的。
最后,我们来看看Handler最核心的实现,消息的处理 Looper.loop(),
忽略非消息处理的代码后如下
public static void loop() {
...
// 获取消息队列
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);
...
msg.recycleUnchecked();
}
}
看着是不是挺简单的呢? 一个for死循环,通过MessageQueue的阻塞方法next 读取下一个Message。
取出来的Message会拿到target成员变量,即Handler,调用dispatchMessage,分发消息。Handler里的分发呢?
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
分发给callback回调,或者Message对象的callback,又或者Handler子类里的handlerMessage。
我们可以调用Looper的quit()方法,让队列安全的关闭,避免不必要的消耗。
或者等待Handler被销毁,让系统自动回收
public void quit() {
mQueue.quit(false);
}
这样Handler的整体的工作原理就是这些了,再见Handler。
网友评论