Handler机制

概述

类 | 说明
Handler | 真正处理事件的地方
Looper | 循环检查是否有要传输的事件，从 MessageQueue 中获取事件，并交给 Handler 处理（假如列队为空就进入休眠）
MessageQueue | 储存需要做的事情，一般来说只允许保存相同类型的 Object、Message 除存的数据结构队列
Message | 需要做的事件

一个 Thread 对应一个 Looper
一个 Looper 对应一个 MessageQueue
一个 MessageQueue 内有多个 Message
每个 Message 中最多对应一个 Handler 处理事件
Thread & Handler 是一对多的关系

Handler

接受处理 Messgae
将 Message 存入 MessageQueue 中

Copy
// Handler.java

public class Handler {
...

final Looper mLooper;
final MessageQueue mQueue;
final Callback mCallback;

...

public interface Callback {
boolean handleMessage(@NonNull Message msg);
}

// 通常用来给使用者 Override 处理事件
public void handleMessage(@NonNull Message msg) {
}

// 分化，有三种方式
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
}

在上面分发事件有三种方法，并且 这三种分发方式有先后顺序，只要前面被处理，就不会使用后面的方式处理
Message 本身的 callback
实现 Callback 接口
Override Handler#handleMessage Function
通过 Handler 把信息入队到 MessageQueue，方式有 Post & Send 两种系列，并且可以控制发送的时间
Post 系列：把零散信息转为 Message 再用 Send 传出

函数 | 功能
boolean post(Runnable r) | 直接发出信息
boolean postAtTime(Runnable, long updatetimeMillis) | 在固定（规定）时间再发出该条信息
Send 系列：参数直接是 Message |

函数 | 功能
boolean sendEmptyMessage(int what) | 直接发送信息
boolean sendMessageArFrontOfQueue(Message msg) | 把消息发送到信息队列最前面
boolean sendMessageAtTime(int what, long updatetimeMillis) | 在固定（规定）时间再发出该条信息
boolean sendMessageDelayed(Message msg, long delayMillis) | 延迟几毫秒后发送该信息

Post 实现方式

Copy
// Handler.java

public class Handler {

public final boolean post(@NonNull Runnable r) {
return sendMessageDelayed(getPostMessage(r), 0);
}

// 包装 callback 再传出
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain(); // 取得 Message 资源，避免不断创建，可以复用资源
m.callback = r; // 直接设定 Runnable 回调函数
return m;
}

// 最后通过计算 当前时间 + 延长实现，之后就呼叫 sendMessageAtTime 函数
public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}

// 在规定时间发送信息
public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
// 若是该 Thread 并没有规定 MessageQueue 则会抛出错误
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}

}

发送信息方法

名称 | 参数：回传 | 解释
post | Runnable : boolean | 接收一个 Runnable 对象作为 Message
postAtTime | Runnable, long : boolean | 接收一个 Runnable 对象作为 Message，并在等待的规定时间发送 Message
sendEmptyMessage | int : boolean | 发送一个使用者规定的 int 信息，在由使用者自己处理
sendMessageAtTime | Messge, int : boolean | 发送一个使用者规定的 int 信息，在由使用者自己处理
sendMessageDelayed | Messge, long : boolean | 在等待的规定时间后 (延迟) 发送 Message

Post & Send

Copy
// Send ...
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}

// Post ...
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}

private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}

// 最终都会 sendMessageAtTime
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) { // 1.
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}

处理 Message

从 dispatchMessage 可看出它预设处理 Message 的顺序
msg.callback (Runnable)
mCallback (interface)
handleMessage (method)

Copy
public void handleMessage(Message msg) {
// 使用者复写
}

/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
// callback 优先级最高
if (msg.callback != null) { // msg.callback is Runnable
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}

MessageQueue & Message

如其名，它是一个队列 FIFO，它通过 本地方法 (Native) 内存指针创建 Queue

Copy
private native static long nativeInit();

MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = nativeInit();
}

Queue 方法

名称 | 参数：回传 | 解释
enqueueMessage | Message, long : boolean | 在指定时间内压入队列中
next | void : Message | 元素拉出队列
removeMessages | Handler, int, Object : void | 移除特定元素
removeMessages | Handler, Runnable, Object : void | 移除特定元素

MessageQueue

MessageQueue 因为是 Queue 所以有所谓的 FIFO, 所以有队列的功能

Copy
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = nativeInit();
}

private native static int nativeInit();

MessageQueue 创建

连接于 Looper 的建构函数，当 Looper 创建时 MessageQueue 就一同创建

Copy
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}

Looper 通过 MessageQueue 取得 Message

Copy
// MessageQueue.java

Message next() {

// 若已经被 depose mPtr 就会被设定为 0
final long ptr = mPtr;
if (ptr == 0) {
return null;
}

int pendingIdleHandlerCount = -1; // -1 only during first iteration

// 下一个信息的时间
int nextPollTimeoutMillis = 0;

// 进入无限循环，也就是说 next 会导致 block
for (;;) {
... 省略部分

synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();

Message prevMsg = null; // 上一个信息
Message msg = mMessages; // 当前信息

if (msg != null && msg.target == null) { // target 就是 Handler

// 找到一个可发送的 Message
do {
prevMsg = msg;
msg = msg.next; // 切换到下一个 Message
} while (msg != null && !msg.isAsynchronous());
}

// 再次判断 Message
if (msg != null) {

// 判断时间
if (now < msg.when) { // 该信息的时间还没到
// Next message is not ready. Set a timeout to wake up when it is ready.
// 计算剩余时间
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// 时间到，并且有 Message
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next; // 上一个 Message 就是当前 Message
} else {
mMessages = msg.next; //切换到下一个要用的 Message
}

// 断开连接 !! 好让 GC 侦测到后回收 !!! (可达性分析)
msg.next = null;

... debug 訊息

msg.markInUse(); // 标记该 Message 已经被使用过
return msg;
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}

// Process the quit message now that all pending messages have been handled.
if (mQuitting) { // 检查是否退出
dispose();
return null;
}

... 省略 IdleHandler
}

... 省略部分
}

IdleHandler

IdleHandler 是 MessageQueue 内的一个 interface，它可以在 MessageQueue 没有消息时让使用者知道，并决定如何处理

Copy
// MessageQueue.java

public static interface IdleHandler {
// 返回true，会让你设定的接口继续存在
// 返回false则会移除你设定的接口
boolean queueIdle();
}

同样分析 next 方法，可以看到一个 MessageQueue 最多设定 4 个 IdleHandler

Copy
// MessageQueue.java

Message next() {

// 若已经被depose mPtr就会被设定为0
final long ptr = mPtr;
if (ptr == 0) {
return null;
}

int pendingIdleHandlerCount = -1; // -1 only during first iteration

// 下一个信息的时间
int nextPollTimeoutMillis = 0;

// 进入无限循环，也就是说next会导致block
for (;;) {
... 省略部分

synchronized (this) {

... 省略部分

// 检查是否有设置IdleHandler
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();

if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
}

// 最多设置4个Idle Handler
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}

// 循环
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; // release the reference to the handler

boolean keep = false;
try {
// 当没有信息时通知接口
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}

// 返回 false 就移除
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}

... 省略部分
}
}

Looper

它是组成消息的重要关键（Handler、Message、MessageQueue），它的角色是驱动

名称 | 参数：回传 | 解释
myLooper | void : Looper | 以当前线程为主，取得当前 Thread 的 Looper
getMainLooper | void : Looper | 取得主线程的 Looper

Looper - ThreadLocal

最后 Looper 则是让整个 Hanler 机制循的动力，有 Looper 的推动 Handler 才能正常接收、发送信息
Looper 中包含了一个 MessageQueue（在构造函数中建构的）

Copy
// ava/android/os/Looper.java

public final class Looper {

// 私有函数
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}

}

当你每创建一个线程就必须为这个线程准备 Looper，否则在 Handler 发送消息时就会 crush（上面有说到会检查），创建主要有以下步骤
Looper 准备工作（prepare 函数）
创建 Handler 发送＆接收消息
Looper 开始运作（loop 函数）

Copy
class LooperThread extends Thread {

private Handler handler;

public void run() {
// 1
Looper.prepare();

// 2.
handler = new Handler() {
@Override
public void handleMessage(Message msg) {
//... 处理 Message
}

}

// 3.
Looper.loop();
}

}

ThreadLocal 这里大概提及，ThreadLocal 也就是线程隔离，使用线程 Thread 作为 Key 储存，而 Value 就是你要拷贝到每个线程的数据（每个子线程都持有一个数据）

Copy
//android/os/Looper.java

public final class Looper {

// 拷贝线程的数据是Looper
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

public static void prepare() {
prepare(true);
}

private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) // 一个线程只能prepare一次
throw new RuntimeException("Only one Looper may be created per thread");
}
// 为当前Thread设定Looper
sThreadLocal.set(new Looper(quitAllowed));
}
}

当你建立一个 Handler 时，在 Handler construct 就会透过当前的线程取得 Looper

Copy
// Handler

public Handler(@Nullable Callback callback, boolean async) {
...
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}

// -----------------------------------------------------------------
// Looper

public static @Nullable Looper myLooper() {
// sThreadLocal是静态的，会透过当前Thread作为Key取得Looper
return sThreadLocal.get();
}

Looper & Handler

Looper 跟 Handler 的关系可以从 new Handler（）这个构造函数中看出，它是透过 myLooper 方法，透过目前的线程在 ThreadLocal 中取得该当前线程所拥有的 Looper

Copy
// Handler construct
public Handler() {
this(null, false);
}

public Handler(Callback callback, boolean async) {
... 忽略

// 取得当前线程的 Loop
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...
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}

Looper & UI Thread

Android 中 Activity 的主线程是 ActivityThread’s main ()

Copy
public static void main(String[] args) {
...

Looper.prepareMainLooper(); //"1. "

ActivityThread thread = new ActivityThread();
thread.attach(false);

if (sMainThreadHandler == null) {
//"2. "
sMainThreadHandler = thread.getHandler();
}

...

// End of event ActivityThreadMain.
...

Looper.loop();

throw new RuntimeException("Main thread loop unexpectedly exited");
}

主线程的 Looper 是不可以关闭的，并且使用类同步

Copy
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 Looper sMainLooper; // guarded by Looper.class

Looper#loop，首先取得目前线程所拥有的 Looper，再取出 Looper 内部有的 MessageQueue，最后无限循环整个消息对列

Copy
// Looper.java

public static void loop() {
final Looper me = myLooper();

...

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;
}

...
try {
// 解决是谁再呼叫dispatchMessage，target为MessageQueue中的Handler
msg.target.dispatchMessage(msg);
end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
...

msg.recycleUnchecked();
}
}

ThreadLocal

ThreadLocal 的功能主要是做到线程隔离（用线程隔离数据），简单来说可以把 ThreadLocal 当作一个 Map（但实际来说它并不是 Map），它的 Key 是 Thread，Value 是一个泛型

Copy
// 前面Looper.prepare（）内部就有使用到set（）方法
public void set(T value) {
Thread t = Thread.currentThread(); //"1. "
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}

// 前面Handler（）构造函数内部就有使用到get（）方法
public T get() {
Thread t = Thread.currentThread(); //"2. "
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}

它使用目前呼叫它的 Thread.currentThread 作为 Key 存入，Value 是泛型
依照当前线程（currentThread），取的 Value