什么是 Handler 先来看看文档中是怎么说的:
A Handler allows you to send and process Message and Runnable objects associated with a thread’s MessageQueue. Each Handler instance is associated with a single thread and that thread’s message queue. When you create a new Handler it is bound to a Looper. It will deliver messages and runnables to that Looper’s message queue and execute them on that Looper’s thread.
意思是说Handler
是一个用于处理Message
和执行Runnable
的工具。每个Thread
都通过Looper
维护一个MessageQueue
。每实例化一个Handler
都需要绑定一个Looper
。Handler
主要功能就是向MessageQueue
中发送Message
和Runnable
,并在Message
被处理的时候执行其中的Runnable
。
可以看到Handler
的背后是一整套的消息流水线机制 ,而Handler
只是我们利用这套机制的入口。
Handler有什么用 通过上面的描述我们大概可以脑补出整套消息流水线机制 的引用关系:
Handler
绑定一个Looper
Looper
由Thread
维护
Looper
内部维护一个MessageQueue
不难发现实际上Handler
是间接绑定了Thread
的。也就是说不同的Handler
可以向不同的线程 发送Message
,在Message
被处理的时候执行回调方法,回到主线程。或者可以直接向主线程中发送消息,或延迟消息进行delay
操作。
这就是为什么要有Handler
:
在Android
系统中需要一个切换线程的工具
同时需要在某些情况下进行delay
操作
这也就是整套消息流水线机制 的作用。
食用消息流水线机制的正确姿势 想要发送Message
共有3种用法:
实例化默认Handler
并向Message
添加Runnable
实例化默认Handler
并通过构造函数传入接口Handler.Callback
实例
继承Handler
重写handleMessage()
方法
当这3种实现方式同时存在的时候,遵循优先级Message.callback > Callback.handleMessage > handleMessage
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public void dispatchMessage (@NonNull Message msg) { if (msg.callback != null ) { handleCallback(msg); } else { if (mCallback != null ) { if (mCallback.handleMessage(msg)) { return ; } } handleMessage(msg); } }
下面来分别看看上面说的3种方式分别如何实现
向Message添加Callback 1 2 3 4 5 6 val h = Handler(Looper.getMainLooper())val msg = Message.obtain(h)val method = msg.javaClass.getMethod("setCallback" , Runnable::class .java)method.invoke(msg, { Log.e("handler test" , "succeed!" ) }) h.sendMessageDelayed(msg, 2000L )
向Handler添加Callback 1 2 3 4 5 6 7 8 9 val h = Handler( Looper.getMainLooper(), Handler.Callback { Log.e("handler test" , "succeed!" ) true }) val msg = Message.obtain(h)h.sendMessageDelayed(msg, 2000L )
继承Handler重写handleMessage() 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 fun postMessage () { val h = CustomizedHandler( Looper.getMainLooper(), WeakReference(this ) ) val msg = Message.obtain(h) h.sendMessageDelayed(msg, 2000L ) } companion object { class CustomizedHandler ( looper: Looper, private val activity: WeakReference<Activity> ) : Handler(looper) { override fun handleMessage (msg: Message ) { super .handleMessage(msg) activity.get ()?.let { Log.e("handler test" , "succeed!" ) } } } }
机制实现原理 从上面的示例种我们可以看出,如果想通过Handler
发送一个Message
并回调处理,需要:
创建Message
实例
通过Looper
创建Handler
实例
通过Handler
发送Message
根据不同情况回调不同处理方法
先上一张网上找的图:
结论先行 整个消息流水线机制 主要分为3部分:
Handler
负责发送Message
和回调handleMessage
方法。
Message
是消息,知道自己应该什么时候被处理和应该回调至哪个Handler
。同时Message
本身是一个链表结构,自己指向下一个Message
形成一个MessageQueue
。
MessageQueue
可以理解为是对上面Message
链表的封装,提供了一些方法对整个队列进行操作。
Looper
可以理解为MessageQueue
的驱动器,通过Looper
不断循环读取MessageQueue
中的第一个节点,进而处理消息。
总体流程是:
Handler
对Message
设置delay
,同时将自己(Handler.this)
设置为Message
的target
,并将其添加至MessageQueue
中。
Looper
不断循环从MessageQueue
中取出Message
,并根据前面提到的优先级决定是否回调Message.target
对应的Handler
。
若回调至Handler
则由Handler
的Callback
或handleMessage(Message)
方法进行处理。
Message 为什么先说Message
呢?通过前面的分析我们可以知道Message
不仅仅是个简单的消息:
可以携带Runnable
回调,被优先处理并拦截Handler
的处理方法
持有Handler
引用,可以回调到特定的Handler
,而Message
本身是要被发送至MessageQueue
中的,也就说明Message
其实是MessageQueue
和Handler
之间通信的桥梁
感性的解释一下,可以把Message
理解为一个跑腿的,Handler
让Message
去银行取钱,Message
去了之后直接去到MessageQueue
中排队,最后排到了自己取完了钱,需要把钱还给Handler
,这时就通过Handler
的引用回调至target handler
的处理方法。
下面来看看Message
的主要成员和方法:
成员 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public int what;public long when;Handler target; Runnable callback; Message next;
构造 Message.obtain()
,一看到obtain
这个字眼,相信只要看过一些源码的同学很快就反应过来了:Message
是池化的。
回顾一下池化 的思想:如果有一个类需要被频繁的实例化,并且存活时间非常短,这个时候创建和销毁的工作就会白白占用很多系统资源,所以为了避免这种情况的发生,需要用一个池
将实例化好的对象保存起来,如果需要使用就尝试去池
中取出实例进行复用。
源码中obtain()
方法很多,一共有7
种重载,但最终调用的还都是这个无参的原始obtain()
方法,下面来看看这个方法中做了什么:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 public static final Object sPoolSync = new Object();private static Message sPool;private static int sPoolSize = 0 ;private static final int MAX_POOL_SIZE = 50 ;public static Message obtain () { synchronized (sPoolSync) { if (sPool != null ) { Message m = sPool; sPool = m.next; m.next = null ; m.flags = 0 ; sPoolSize--; return m; } } return new Message(); }
Handler 构造 我们直接来看Handler
的常用构造函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 final Looper mLooper;final MessageQueue mQueue;final Callback mCallback;@Deprecated public Handler () { this (null , false ); } @Deprecated public Handler (@Nullable Callback callback) { this (callback, false ); } public Handler (@NonNull Looper looper) { this (looper, null , false ); } public Handler (@NonNull Looper looper, @Nullable Callback callback) { this (looper, callback, false ); } @UnsupportedAppUsage public Handler (@NonNull Looper looper, @Nullable Callback callback, boolean async) { mLooper = looper; mQueue = looper.mQueue; mCallback = callback; mAsynchronous = async; }
可以看出Handler
的构造其实非常直接:
持有一个Looper
引用
通过Looper
持有一个MessageQueue
引用
一个可空的Handler.Callback
设置是否发送异步消息
关于异步消息后面会单独讲,这里先不过多描述,总的来说Handler
的初始化就是给mLooper
,mQueue
和mCallback
赋值。
发送消息 Handler
中有n多用于发送消息的方法,由于实在太多在这里就不一一细说了。
但是这些方法都有一个共性,无论哪个发送Message
的方法最终都会调用到sendMessageAtTime
方法:
1 2 3 4 5 6 7 8 9 10 11 12 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); }
继续跟进enqueueMessage()
方法:
1 2 3 4 5 6 7 8 9 10 11 12 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); }
回调 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public void dispatchMessage (@NonNull Message msg) { if (msg.callback != null ) { handleCallback(msg); } else { if (mCallback != null ) { if (mCallback.handleMessage(msg)) { return ; } } handleMessage(msg); } }
稍微总结一下,Handler
其实就是一个发送器/接收器
,用来将Message
发送到MessageQueue
中,当消息被处理之后会通过Message.target
回调至Handler
中进行处理。
MessageQueue 因为消息量大且数量不固定,所以不可能同时处理所有Message
,这个时候就需要对大量的Message
排队处理。
Message
链表本身就形成了一个队列,但是并不能简单的根据这个链表结构利用起队列的特性,所以通过MessageQueue
将整个链表进行了封装,对外提供对于队列
的操作方式。
构造 先来看一看MessageQueue
的构造方法:
1 2 3 4 5 6 7 8 9 10 private final boolean mQuitAllowed;private long mPtr; MessageQueue(boolean quitAllowed) { mQuitAllowed = quitAllowed; mPtr = nativeInit(); }
可以看到MessageQueue
的构造方法非常简单,只是初始化了两个标志:
入队 这里就是Handler
发送消息最终调用到的方法,直接来看代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 boolean enqueueMessage (Message msg, long when) { 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(); msg.when = when; Message p = mMessages; boolean needWake; if (p == null || when == 0 || when < p.when) { 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; prev.next = msg; } if (needWake) { nativeWake(mPtr); } } return true ; }
同步屏障(sync barriers) 关于同步屏障前面已经介绍过了,其作用就是将MessageQueue
阻塞起来,同时优先处理MessageQueue
中的异步消息。
我们先来看看用于添加同步屏障的方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 @UnsupportedAppUsage public int postSyncBarrier () { return postSyncBarrier(SystemClock.uptimeMillis()); } private int postSyncBarrier (long when) { synchronized (this ) { final int token = mNextBarrierToken++; final Message msg = Message.obtain(); msg.markInUse(); msg.when = when; msg.arg1 = token; Message prev = null ; Message p = mMessages; if (when != 0 ) { while (p != null && p.when <= when) { prev = p; p = p.next; } } if (prev != null ) { msg.next = p; prev.next = msg; } else { msg.next = p; mMessages = msg; } return token; } }
再来看一看移除同步屏障的方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 @UnsupportedAppUsage public void removeSyncBarrier (int token) { synchronized (this ) { Message prev = null ; Message p = mMessages; while (p != null && (p.target != null || p.arg1 != token)) { prev = p; p = p.next; } if (p == null ) { throw new IllegalStateException("The specified message queue synchronization " + " barrier token has not been posted or has already been removed." ); } final boolean needWake; if (prev != null ) { prev.next = p.next; needWake = false ; } else { mMessages = p.next; needWake = mMessages == null || mMessages.target != null ; } p.recycleUnchecked(); if (needWake && !mQuitting) { nativeWake(mPtr); } } }
可以看到这两个方法都被标记为对app不可见,如果需要使用的话只能通过反射调用。
遍历(next) 这个方法其实就是Looper
用来遍历MessageQueue
的方法。这个方法比较长,中间还涉及到了阻塞的逻辑,需要静下心来看一看:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 @UnsupportedAppUsage Message next () { final long ptr = mPtr; if (ptr == 0 ) { return null ; } int pendingIdleHandlerCount = -1 ; int nextPollTimeoutMillis = 0 ; for (;;) { if (nextPollTimeoutMillis != 0 ) { Binder.flushPendingCommands(); } nativePollOnce(ptr, nextPollTimeoutMillis); synchronized (this ) { final long now = SystemClock.uptimeMillis(); Message prevMsg = null ; Message msg = mMessages; if (msg != null && msg.target == null ) { do { prevMsg = msg; msg = msg.next; } while (msg != null && !msg.isAsynchronous()); } if (msg != null ) { if (now < msg.when) { nextPollTimeoutMillis = (int ) Math.min(msg.when - now, Integer.MAX_VALUE); } else { mBlocked = false ; if (prevMsg != null ) { prevMsg.next = msg.next; } else { mMessages = msg.next; } msg.next = null ; if (DEBUG) Log.v(TAG, "Returning message: " + msg); msg.markInUse(); return msg; } } else { nextPollTimeoutMillis = -1 ; } if (mQuitting) { dispose(); return null ; } if (pendingIdleHandlerCount < 0 && (mMessages == null || now < mMessages.when)) { pendingIdleHandlerCount = mIdleHandlers.size(); } if (pendingIdleHandlerCount <= 0 ) { mBlocked = true ; continue ; } 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 ; boolean keep = false ; try { keep = idler.queueIdle(); } catch (Throwable t) { Log.wtf(TAG, "IdleHandler threw exception" , t); } if (!keep) { synchronized (this ) { mIdleHandlers.remove(idler); } } } pendingIdleHandlerCount = 0 ; nextPollTimeoutMillis = 0 ; } }
可以看next()
方法中的工作还是比较多的
处理可以立即执行的消息
如果有同步屏障则优先处理异步消息
如果没有可以立即处理的消息就将队列阻塞起来
阻塞的时候根据情况决定是否回调IdleHandler
退出 下面来看看MessageQueue
是如何退出的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 void quit (boolean safe) { if (!mQuitAllowed) { throw new IllegalStateException("Main thread not allowed to quit." ); } synchronized (this ) { if (mQuitting) { return ; } mQuitting = true ; if (safe) { removeAllFutureMessagesLocked(); } else { removeAllMessagesLocked(); } nativeWake(mPtr); } }
重要的地方需要再次强调一下,quit
方法并不是立刻真正退出,而是将类成员mQuitting
设置为true
。
在Looper
通过MessageQueue.next()
方法对消息队列进行遍历的时候,如果遇到mQuitting == true
再去执行真正的退出。
这样的好处就是,一切行为都由Looper
去触发,MessageQueue
只负责维护Message
以及记录状态。
Looper 到目前为止我们了解了Message
,MessageQueue
和Handler
,可以知道Handler
由用户根据不同情况和用法自行实例化,Message
是通过Message.obtain()
从消息池中获取的。
似乎到目前为止还不知道MessageQueue
是由谁创建和维护的。
这个宿主就是接下来要讲的Looper
。
Looper
的类名可以说是顾名思义,只负责一个事儿,就是loop()
。在loop()
的过程中通过调用MessageQueue.next()
来不断地从消息队列中获取消息并处理。
构造 我们先来看看Looper
是如何实例化的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 @UnsupportedAppUsage static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();@UnsupportedAppUsage final MessageQueue mQueue;final Thread mThread;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)); } private Looper (boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
关于ThreadLocal
,如果想详细了解的话可以看这篇 -> 理解ThreadLocal
可以看出Looper.prepare()
完成了对Looper
和MessageQueue
的初始化,并把Looper
存入ThreadLocalMap
中。
循环(loop) 这里不废话了,直接上代码讲:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 public static void loop () { final Looper me = myLooper(); if (me == null ) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread." ); } me.mInLoop = true ; final MessageQueue queue = me.mQueue; for (;;) { Message msg = queue.next(); if (msg == null ) { return ; } try { msg.target.dispatchMessage(msg); } catch (Exception exception) { throw exception; } finally { ThreadLocalWorkSource.restore(origWorkSource); if (traceTag != 0 ) { Trace.traceEnd(traceTag); } } msg.recycleUnchecked(); } }
退出 这个其实没什么好讲的了…
1 2 3 4 5 6 7 public void quit () { mQueue.quit(false ); } public void quitSafely () { mQueue.quit(true ); }
稍微梳理一下
在主线程启动的时候就在主线程 自动启动了一个Looper
Looper
内部实例化了一个MessageQueue
用来维护消息
Looper不停循环通过MessageQueue.next()
方法从队列中拿出Message
进行处理
MessageQueue.next()
方法中会判断当前有没有可以处理的Message
,如果没有回将整个队列阻塞起来(epoll唤醒)
用户通过Handler
向MessageQueue
发送消息
Message
持有Handler
的引用,在被处理的时候可以通过Message.target
回调至对应的Handler
中进行处理
关于死循环 相信了解过Handler
就一定会停过一个问题:
Looper.loop()
启动了一个死循环,为什么没有阻塞主线程?
说这个问题之前我要先提个醒,这个题有坑!
如果顺着题的思路去考虑“为什么死循环没有阻塞线程”的话就完全跑偏了。
以我们的App
来举例子:
我们知道一个Activity
如果不去主动退出的
我们知道Activity
是运行在自己的线程中的
我们知道启动一个线程,线程的任务执行完成后会自动退出
仔细想想上面说的这三个事儿,很明显逻辑是有问题的,而问题就在Looper
上。不妨思考一下,如何让一个线程不主动退出?
答案就是死循环 。
回到上面的问题中,可以发现这个题本身就是个大坑:
死循环不会阻塞主线程的原因是,死循环本身就是这个线程的主要任务!
再来想一想Looper
是干嘛的?Looper
是从MessageQueue
里面取出消息并回调Handler
处理的。当队列没有消息的时候证明主线程也不再需要刷新任何UI,也不需要处理任何数据,所以为了不让Looper
空转导致资源浪费才有了MessageQueue
的阻塞机制。
另外一个问题,整个线程处于死循环中,那么外部的事件是如何进入到MessageQueue
中的呢?
其实这个问题也很容易理解,我们知道Activity
全是由AMS
统一维护的,Activity
在启动的时候就和AMS
建立了联系,如果有外部事件(触摸等)需要被处理的话,会由AMS
通过App
中的其他线程将Message
抛到主线程的MessageQueue
中。
总结 没啥可总结的了,也不是一句两句能总结完的。
这里就先把前面梳理的流程再贴一遍:
在主线程启动的时候就在主线程 自动启动了一个Looper
Looper
内部实例化了一个MessageQueue
用来维护消息
Looper不停循环通过MessageQueue.next()
方法从队列中拿出Message
进行处理
MessageQueue.next()
方法中会判断当前有没有可以处理的Message
,如果没有回将整个队列阻塞起来(epoll唤醒)
用户通过Handler
向MessageQueue
发送消息
Message
持有Handler
的引用,在被处理的时候可以通过Message.target
回调至对应的Handler
中进行处理
最好的总结就是翻回去再看一遍~
Over.