Handler 介绍
Handler 允许你发送和处理与线程的 MessageQueue 关联的 Message 和 Runnable 对象。每个 Handler 实例都与一个线程和该线程的消息队列相关联。当你创建一个新的 Handler 时,它会绑定到一个 Looper。它会将消息和可运行对象传递到该 Looper 的消息队列,并在该 Looper 的线程上执行它们。
Handler 有两个主要用途:
- 1、安排消息和可运行对象在将来的某个时间执行;
- 2、将要在与您自己的线程不同的线程上执行的操作排入 队列 。
主要场景是子线程完成耗时操作的过程中,通过 Handler 向主线程发送消息 Message,用来刷新 UI 界面。 本文咱们来了解 Handler 的发送消息和处理消息的源码实现。
分析源码的时候最好是找到一个合适的切入点,Handler 源码的一个切入点就是它的默认构造器。
分析源码
new Handler()
public Handler() { this(null, false); } public Handler(@Nullable Callback callback, boolean async) { //发现泄露,初始值false,不看往下走 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()); } } //注释1 mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread " + Thread.currentThread() + " that has not called Looper.prepare()"); } //注释2 mQueue = mLooper.mQueue; //null mCallback = callback; //false mAsynchronous = async; }
在无参构造器里调用了重载的构造方法并分别传入 null 和 false。并且在构造方法中给两个全局变量赋值:mLooper 和 mQueue。mLooper是通过 Looper 来获取。mQueue 是通过 mLooper.mQueue 获取。这说明他们都来找于 Looper 。咱们先看myLooper吧。
Looper.myLooper()
final MessageQueue mQueue; public static @Nullable Looper myLooper() { return sThreadLocal.get(); }
sThreadLocal.get()
public T get() { Thread t = Thread.currentThread(); 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(); }
可以看出,myLooper 通过一个线程本地变量中的存根,然后 mQueue 是 Looper 中的一个全局变量,类型是 MessageQueue 类型。
MessageQueue:保存要由 Looper 调度的消息列表。 Message不是直接添加到 MessageQueue 的,而是通过与 Looper 关联的 Handler 对象添加的。你可以使用 Looper.myQueue() 检索当前线程的 MessageQueue。
Looper 介绍
默认情况下,线程没有与之关联的消息循环;要创建一个,在运行循环的线程中调用 prepare ,然后循环让它处理消息,直到循环停止。
大多数与消息循环的交互是通过 Handler 类进行的。
这是一个Looper线程实现的典型例子,利用prepare和loop的分离,创建了一个初始Handler与Looper进行通信。
class LooperThread extends Thread { public Handler mHandler; public void run() { Looper.prepare(); mHandler = new Handler(Looper.myLooper()) { public void handleMessage(Message msg) { // 在这里处理传入的消息 } }; Looper.loop(); } }
启动一个 java 程序的入口函数是 main 方法,但是当 main 函数执行完毕之后此程序停止运行,也就是进程会自动终止。
但是当我们打开一个 Activity 之后,只要我们不按下返回键 Activity 会一直显示在屏幕上,也就是 Activity 所在进程会一直处于运行状态。实际上 Looper 内部维护一个无限循环,保证 App 进程持续进行。
Looper初始化
Activity.attach() 方法中会传入一个ActivityThread,ActivityThread 的 main 方法是一个新的 App 进程的入口。
ActivityThread.main()
public static void main(String[] args) { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain"); // 安装选择性系统调用拦截 AndroidOs.install(); // 禁止CloseGuard CloseGuard.setEnabled(false); Environment.initForCurrentUser(); //确保 TrustedCertificateStore 查找 CA 证书的正确位置 final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId()); TrustedCertificateStore.setDefaultUserDirectory(configDir); // 调用每个进程的主线模块初始化。 initializeMainlineModules(); Process.setArgV0("<pre-initialized>"); //重点:注释1 //初始化当前进程的 Looper 对象 Looper.prepareMainLooper(); ... ActivityThread thread = new ActivityThread(); thread.attach(false, startSeq); if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); } ... //重点:注释2 //调用 Looper 的 loop 方法开启无限循环。 Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); }
注释1:就初始化当前进程的 Looper 对象;
注释2:调用 Looper 的 loop 方法开启无限循环(具体下面讲到)。
Looper.prepareMainLooper()
1. public static void prepareMainLooper() { //注释1:创建一个Looper //下面把方法贴出来 prepare(false); //加个同步方法对象锁 synchronized (Looper.class) { if (sMainLooper != null) { throw new IllegalStateException("The main Looper has already been prepared."); } //这个要等prepare执行完再看 //注释1 sMainLooper = myLooper(); } }
Looper.prepare()
private static void prepare(boolean quitAllowed) { //判断是否绑定过 Looper 对象 if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper(quitAllowed)); }
Looper.prepare 方法其实就是new 一个 Looper。核心之处在于将 new 出的 Looper 设置到了线程本地变量 sThreadLocal.set(looper) 中。也就是说创建的 Looper 与当前线程发生了绑定。
注意:在创建 Looper 对象之前,会判断 sThreaLocal 中是否已经绑定过 Looper 对象,如果是则抛出异常。这行代码的目的是确保在一个线程中 Looper.prepare() 方法只能被调用 1 次。
new Looper()
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
Looper在构造方法中初始化了消息队列 MessageQueue 对象。
prepare 方法执行完之后,会在 Looper.prepareMainLooper 中处调用 myLooper() 方法,从 sThreadLocal 中取出 Looper 对象并赋值给 sMainLooper 变量。
Looper.prepare() 只能被调用1次
从上面代码可以看出Activity在被创建时已经在 Looper.prepareMainLooper()中调用了一次Looper.prepare(),我决定在onCreate()里面再调用一次Looper.prepare(),祝福我吧。 我现在我准备在MainActivity中加一行代码
@Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Looper.prepare(); }
结果惨兮兮:
注意:
- prepare 方法在一个线程中只能被调用 1 次;
- Looper 的构造方法在一个线程中只能被调用 1 次;
- MessageQueue 在一个线程中只会被初始化 1 次。
结论:也就是说 UI 线程中只会存在 1 个 MessageQueue 对象,后续我们通过 Handler 发送的消息都会被发送到这个 MessageQueue 中。
Looper 干啥的?
总结 Looper 做的事情就是:不断从 MessageQueue 中取出 Message,然后处理 Message 中指定的任务。
回到原点,在 ActivityThread 的 main 方法中,除了调用 Looper.prepareMainLooper 初始化 Looper 对象之外,还调用了 Looper.loop 方法开启无限循环,Looper 的主要功能就是在这个循环中完成的。
Looper.loop()
public static void loop() { //取出 Looper 对象并赋值给 me final Looper me = myLooper(); if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } if (me.mInLoop) { Slog.w(TAG, "Loop again would have the queued messages be executed" + " before this one completed."); } me.mInLoop = true; final MessageQueue queue = me.mQueue; ... //下面这个死循环,进去就甭想出来了。 for (;;) { //注释1 //调用 MessageQueue 的 next 方法取出 Message Message msg = queue.next(); // might block if (msg == null) { // No message indicates that the message queue is quitting. return; } ... try { //注释2 //msg不为null,进行处理 msg.target.dispatchMessage(msg); if (observer != null) { observer.messageDispatched(token, msg); } dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0; } catch (Exception exception) { if (observer != null) { observer.dispatchingThrewException(token, msg, exception); } throw exception; } finally { ThreadLocalWorkSource.restore(origWorkSource); if (traceTag != 0) { Trace.traceEnd(traceTag); } } ... msg.recycleUnchecked(); } }
上面代码表示 loop 方法中执行了一个死循环,这也是一个 Android App 进程能够持续运行的原因。
注释1:不断地调用 MessageQueue 的 next 方法取出 Message。
注释2:如果 message 不为 null,则处进行后续处理。具体就是从 Message 中取出 target 对象,然后调用其 dispatchMessage 方法处理 Message 自身。target是谁?
Message.target
public final class Message implements Parcelable { ... @UnsupportedAppUsage @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) public long when; /*package*/ Bundle data; @UnsupportedAppUsage /*package*/ Handler target; @UnsupportedAppUsage /*package*/ Runnable callback; // sometimes we store linked lists of these things @UnsupportedAppUsage /*package*/ Message next; /** @hide */ public static final Object sPoolSync = new Object(); private static Message sPool; private static int sPoolSize = 0; ... }
查看后其实就是个Handler。那咱们再看看Handler 的 dispatchMessage 方法
Handler.dispatchMessage()
/** * Handle system messages here. * 在这里处理系统消息。 */ public void dispatchMessage(@NonNull Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } } /** * Subclasses must implement this to receive messages. * 子类必须实现它才能接收消息。 */ public void handleMessage(@NonNull Message msg) { }
可以看出,在 dispatchMessage 方法中会调用一个空方法 handleMessage,而这个方法也正是我们创建 Handler 时需要覆盖的方法。那么 Handler 是何时将其设置为一个 Message 的 target 的呢?
Handler.sendMessage()
Handler 有几个重载的 sendMessage 方法,但是基本都大同小异。咱使用最普通的 sendMessage 方法来分析,代码具体如下:
public final boolean sendMessage(@NonNull Message msg) { return sendMessageDelayed(msg, 0); }
Handler.sendMessageDelayed()
public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) { if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); }
Handler.sendMessageAtTime()
1. public boolean sendMessageAtTime(@NonNull 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); }
经过几层调用之后,在这里我们拿到了在 ActivityThread 的 main 方法中通过 Looper 创建的 MessageQueue。
并且最后调用 enqueueMessage 方法将 Message 插入到消息队列 MessageQueue 中。
Handler.emqueueMessage()
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg, long uptimeMillis) { //注释 msg.target = this; msg.workSourceUid = ThreadLocalWorkSource.getUid(); if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
注释:将 Handler 自身设置为 Message的target(Handler) 对象。下来咱们看看 MessageQueue 的 enqueueMessage 方法。因此后续 Message 会调用此 Handler 的 dispatchMessage 方法来处理。
MessageQueue.enqueueMessage()
boolean enqueueMessage(Message msg, long when) { //注释1,非空判断 if (msg.target == null) { throw new IllegalArgumentException("Message must have a target."); } synchronized (this) { if (msg.isInUse()) { throw new IllegalStateException(msg + " This message is already in use."); } if (mQuitting) { IllegalStateException e = new IllegalStateException( msg.target + " sending message to a Handler on a dead thread"); Log.w(TAG, e.getMessage(), e); msg.recycle(); return false; } msg.markInUse(); //注释2,从这朝下都蛮重要的 msg.when = when; Message p = mMessages; boolean needWake; if (p == null || when == 0 || when < p.when) { // New head, wake up the event queue if blocked. msg.next = p; mMessages = msg; needWake = mBlocked; } else { needWake = mBlocked && p.target == null && msg.isAsynchronous(); Message prev; for (;;) { 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) { nativeWake(mPtr); } } return true; }
注释1:会判断msg.target == null 没有设置,则直接抛出异常;
注释2:会按照 Message 的时间 when 来有序得插入 MessageQueue 中,可以看出 MessageQueue 实际上是一个有序队列,只不过是按照 Message 的执行时间来排序。
后续就是通过 ActivityThread 的 main 方法中 Looper 创建的 MessageQueue。Looper 从 MessageQueue 中取出 Message 之后,会调用 dispatchMessage 方法进行处理。
至此 Handler 的发送消息和消息处理流程已经介绍完毕。