Handler 作为 Android 开发中重要的消息通讯的工具,在我们日常开发中经常使用到,虽然经藏使用,也是一知半解,所以今天就去看一下 Handler 的源码到底怎么实现的呢?
1 Handler 是什么呢?
众 android 开发者周知, Handler 是我们用来进行线程间通讯的工具。像我们网络请求返回的数据,就会经常使用Handler把数据回传给主线程。然后主线程展示相关数据。
2 为什么要用 Handler 呢?
android 要求耗时的任务要在子线程中进行,不然会造成UI界面的卡顿,而我们的 UI 界面是在主线程。要把子线程的数据显示到主线程则就要用到 handler 了,不然,你在子线程直接刷新UI界面,程序会报错。
3 看下我们平时如何用 Handler 的呢?
public class TestActivity extends AppCompatActivity {
Handler handler = new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
switch (msg.what){
case 0x1111:
Toast.makeText(this,"收到子线程发来的消息了",Toast.LENGTH_LONG).show();
break;
}
}
};
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
new Thread(){
@Override
public void run() {
Message message = Message.obtain();
message.obj = "这是一个handler消息";
message.what = 0x1111;
handler.sendMessage(message);
}
};
}
}
上面代码是我们 Handler 的常用方式,接下来去看下它内部具体是怎么实现的呢?进入源码中去查看;
Handler 的构造方法
(1) 首先咱们看一下创建Handler都去做了哪些工作。
Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
调用构造方法:
public Handler() {
this(null, 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) {// 判断Handler 是否为静态修饰
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
mLooper = Looper.myLooper();// 获取 looper
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;// looper 的 mQueue 值赋值给 Handler 类中 mQueue
mCallback = callback;
mAsynchronous = async;
}
可以看到 handler 构造的过程中,如果定义 handler 没有用 static 修饰符的话,还会提示你会出现内存溢出的风险(这里和 Handler 持有 Activity 有关);
接下来会去获取到一个 Looper 对象。同时把 Looper 类里面的消息队列 mLooper.mQueue 赋值给了 Handler 类里面的队列常量 mQueue;
先继续查看 Looper 获取情况。
mLooper = Looper.myLooper();
进入到Looper类中。
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
static final ThreadLocal sThreadLocal = new ThreadLocal();
private static Looper sMainLooper; // guarded by Looper.class
final MessageQueue mQueue;
在 Looper 类里面维护了一个 sThreadLocal 的变量,我们获取到的 looper 是从这个变量中取的。
sThreadLocal 实际是一个 ThreadLocal 类,ThreadLocal 是一个线程内部的存储类,可以在指定线程内存储数据,数据存储以后,只有指定线程可以得到存储数据。
ThreadLocal
public class ThreadLocal {
public ThreadLocal() {}
public T get() {//获取
// Optimized for the fast path.
Thread currentThread = Thread.currentThread();
Values values = values(currentThread);//获取到当前线程的 values
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);
}
public void set(T value) { // 存储
Thread currentThread = Thread.currentThread();// 获取到当前线程
Values values = values(currentThread);
if (values == null) {
values = initializeValues(currentThread);
}
values.put(this, value);
}
可以看到 ThreadLocal 内部为了类 Values,而存储数据以 key、value的方式存储在了 values 中。
key---ThreadLocal 类,value---将要存储的值。这里看到 values 是和 线程有关系,那么 ThreadLocal 在不同线程中取到的 values 值肯定是不同的。实际上不同的线程对应的也是不同的 ThreadLocal 对象;
ThreadLocal 的与线程之间关系可简单表示为上述的关系;
既然在 Handler 构造过程中通过 ThreadLocal 去取 Looper 实例,那么就一定会有存储 Looper 实例的地方。
我们一般都在主线程去进行 Handler 的构造,那么这里就假定在主线程中的操作;
这里直接定位到 ActivityThread 中,即系统运行的主线程:
public static void main(String[] args) {
SamplingProfilerIntegration.start();
// CloseGuard defaults to true and can be quite spammy. We
// disable it here, but selectively enable it later (via
// StrictMode) on debug builds, but using DropBox, not logs.
CloseGuard.setEnabled(false);
Environment.initForCurrentUser();
// Set the reporter for event logging in libcore
EventLogger.setReporter(new EventLoggingReporter());
Security.addProvider(new AndroidKeyStoreProvider());
// Make sure TrustedCertificateStore looks in the right place for CA certificates
final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
TrustedCertificateStore.setDefaultUserDirectory(configDir);
Process.setArgV0("");
Looper.prepareMainLooper();// 准备主线程的 looper 对象
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
Looper.loop(); // 开启 loop 循环查询消息
throw new RuntimeException("Main thread loop unexpectedly exited");
}
在 ActivityThread 的 main 方法中, 调用 Looper.prepareMainLooper() 方法去准备主线程的 Looper;
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
public static void prepare() {// 准备looper
prepare(true);
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {// 每个线程只能有一个looper 对象
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
到这里发现了在主线程开始的时候,便初始化了 Looper ,设置对应的 Looper 在 ThreadLocal 中,且每个线程只对应一个 Looper 对象;
通过上述过程我们知道了,在 Handler 的构造过程中,会通过 ThreadLocal 类去拿到对应线程的 Looper 对象,这里 Looper 对象获取了为后续的发送消息做准备。
另外,Handler 构造过程中同时将 Looper 的 MessageQuene 赋值给了 Handler 的 MessageQuene ;
mQueue = mLooper.mQueue;// looper 的 mQueue 值赋值给 Handler 类中 mQueue
MessageQuene
public final class MessageQueue {
// True if the message queue can be quit.
private final boolean mQuitAllowed;
@SuppressWarnings("unused")
private long mPtr; // used by native code
Message mMessages;
private final ArrayList mIdleHandlers = new ArrayList();
private IdleHandler[] mPendingIdleHandlers;
private boolean mQuitting;
// Indicates whether next() is blocked waiting in pollOnce() with a non-zero timeout.
private boolean mBlocked;
// The next barrier token.
// Barriers are indicated by messages with a null target whose arg1 field carries the token.
private int mNextBarrierToken;
private native static long nativeInit();
private native static void nativeDestroy(long ptr);
private native static void nativePollOnce(long ptr, int timeoutMillis);
private native static void nativeWake(long ptr);
private native static boolean nativeIsIdling(long ptr);
}
MessageQuene 主要定义了一些常量以及和 c 交互的方法,那么直接去 Looper 中查看使用 MessageQuene 的地方;
在 ActivityThread 的 main 方法中,会调用 Looper 的 loop 方法,直接从这里入手查看 Looper 与 MessageQuene 的关联;
public static void loop() {
final Looper me = myLooper();// 获取当前线程的looper
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue; // 通过 looper 获取到队列
// 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;
}
// This must be in a local variable, in case a UI event sets the logger
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
msg.target.dispatchMessage(msg);// 分发获取到的 msg 信息
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
msg.recycleUnchecked();
}
}
可以看到,loop 方法中有个无限循环去从 MessageQuene 中取下一个消息。只有取到的消息为 null 的时候才会退出这个无限循环。
查看 MessageQuene 的 next 方法去取消息;
Message next() {
......
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) { //无限循环
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
nativePollOnce(ptr, nextPollTimeoutMillis); // 调用 native 的方法
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) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
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 {
// Got a message.
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (false) Log.v("MessageQueue", "Returning message: " + msg);
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;
}
......
}
}
这里的 next 方法同样挂起了一个无限循环,那么就有一个疑问,为什么 MessageQuene 开启一个无限循环不会导致程序的卡死崩溃呢?
这里就和 nativePollOnce 这个方法有关了,nativePollOnce 通过底层阻塞住,直到 MessageQuene 中有消息将其唤醒,通过 nativeWake 方法进行唤醒取到消息。实际通过底层的阻塞状态来进行是否读取消息,并不会导致阻塞线程,具体底层不在此文讨论。可自行查看 c 代码;
当 Handler 处有消息进行发送的时候,此时 MessageQuene 的 next 方法会获取到消息 Message ,然后会通过 msg.target.dispatchMessage(msg) 进行分发消息;
到这里,总结下 Handler 初始化之前以及初始化的过程都做了哪些事情:
1、ActivityThread 会准备 Looper,同时通过 ThreadLocal 类将线程和 Looper 绑定后存储在 ThreadLocal中;
2、Looper 中的 MessageQuene 赋值给 Handler 中的 MessageQuene 变量;
3、Activity 初始化的 Looper 开启 loop 方法对 MessageQuene 进行消息循环获取;获取到
Handler 发送来的消息后,通过 dispatchMessage 方法进行分发;
接下来,继续查看 Handler 发送消息的源码;
Handler 发送消息
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);
}
Handler 通过 sendMessage 发送消息,最终会调用到 enqueueMessage 方法,同时如果有延迟发送,会将延迟时间传入;
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this; // msg 的 taget 指向 此Handler
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
Handler 的 enqueueMessage 方法最终会调用到 MessageQueue 的 enqueueMessage 方法;而 mQueue 在 Handler 的初始化方法中提到过,其实是由 Looper 中的 MessageQueue 赋值的,所以 Handler 中的变量 mQueue 其实是和 Looper 中的变量 mQueue 一样的;
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) {
if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w("MessageQueue", e.getMessage(), e);
msg.recycle();
return false;
}
msg.markInUse();
msg.when = when;//
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) { // msg 插如队列头部
// 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 (;;) { // 无限循环 msg 放到 队列的尾部
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) { // 是否需要通知 native 唤醒队列
nativeWake(mPtr);
}
}
return true;
}
MessageQuene 的 enqueueMessage 方法会去将 msg 插入到双向队列之中,发送的 msg 信息到最后一位,如果需要唤醒队列读取 msg 消息,调用 nativeWake 方法;
在上面 Looper 的 loop 方法中有提到如果 MessageQuene 中没有消息就会底层阻塞住读取消息,而当我们发送消息的时候,nativeWake 则会将阻塞状态转成运行状态,此时 loop 方法读取到 msg 消息;
那么我们就又回到了 dispatchMessage 方法了,而进行分发消息的则是 msg.target,即 Handler 类处理;
dispatchMessage 方法
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);// 回调 handleMessage 方法
}
}
很明显,dispatchMessage 方法会回调到 Handler 重写的 handleMessage 方法;到此整个 Handler 的处理过程形成了闭环;
最后,将Handler、Looper、Message、MessageQuene、ThreadLocal 形成一个闭环,看下整个过程的大致图解:
最后还有个问题,如果是在子线程里面可以创建 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();
}
}
上面是Looper 类上面的注释,子线程也可以去用来处理接受消息,主线程里面 ActivityThread 方法会帮助我们去调用 Looper.prepare()方法,从而设置 Looper 实例,而在子线程里面则需要自己进行创建,保证用于 Looper 实例可以去循环取消息了;