|
| 1 | +### Handler, Looper, Message Queue, Runnable源码分析 |
| 2 | + |
| 3 | +大家做Android开发难免不和这几个哥们打交道。而且基本上,面试必问。为了学习,也为了搞清楚这个东西,我决定从源码的角度分析这几个哥们。 |
| 4 | + |
| 5 | +首先说一下关系: |
| 6 | + |
| 7 | +- `Runnable`和`Message`可以放入某个`MessageQueue`里面,形成一个集合 |
| 8 | +- `Looper`循环的从`Message Queue`里面取出一个东西,交由`Handler`进行处理 |
| 9 | +- `Handler`才是真正干活的地方 |
| 10 | + |
| 11 | + |
| 12 | + |
| 13 | + |
| 14 | + |
| 15 | +既然`Handler`才是干活的,我们来先看看这个哥们长啥样子。 |
| 16 | + |
| 17 | +源码代码位置:`$ANDROID_BASE/frameworks/base/core/android/os/Handler.java` |
| 18 | + |
| 19 | +`$ANDROID_BASE/frameworks/base/core/android/os/Looper.java` |
| 20 | + |
| 21 | +`$ANDROID_BASE/frameworks/base/core/android/os/MessageQueue.java` |
| 22 | + |
| 23 | +`Handler.java`: |
| 24 | + |
| 25 | +```java |
| 26 | +public class Handler { |
| 27 | + ... |
| 28 | + |
| 29 | + final Looper mLooper; |
| 30 | + final MessageQueue mQueue; |
| 31 | + final Callback mCallback; |
| 32 | +} |
| 33 | +``` |
| 34 | + |
| 35 | +`Looper.java` |
| 36 | + |
| 37 | +```java |
| 38 | +public final class Looper { // 注意这里的final 关键字 |
| 39 | + ... |
| 40 | + // sThreadLocal.get() will return null unless you've called prepare(). |
| 41 | + @UnsupportedAppUsage |
| 42 | + static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); |
| 43 | + @UnsupportedAppUsage |
| 44 | + private static Looper sMainLooper; // guarded by Looper.class |
| 45 | + private static Observer sObserver; |
| 46 | + |
| 47 | + @UnsupportedAppUsage |
| 48 | + final MessageQueue mQueue; |
| 49 | + final Thread mThread; |
| 50 | + |
| 51 | +} |
| 52 | +``` |
| 53 | + |
| 54 | +`MessageQueue.java` |
| 55 | + |
| 56 | +```java |
| 57 | +public final class MessageQueue { |
| 58 | + ... |
| 59 | + Message message; |
| 60 | +} |
| 61 | +``` |
| 62 | + |
| 63 | + |
| 64 | + |
| 65 | +可以发现: |
| 66 | + |
| 67 | +1. 一个线程,只有一个Looper |
| 68 | +2. 一个Looper,只有一个MessageQueue |
| 69 | +3. 一个MessageQueue有多个Message |
| 70 | +4. 一个Message最多指定一个Handler来处理。 |
| 71 | + |
| 72 | +继续看源码,我们可以发现`Handler`主要这么两个职责: |
| 73 | + |
| 74 | +- 处理`Message` |
| 75 | +- 将某个`Message`发送出去(放到MessageQueue中) |
| 76 | + |
| 77 | +来看看`Looper`取出消息分发的相关代码: |
| 78 | + |
| 79 | +```java |
| 80 | +public static void loop() { |
| 81 | + final Looper me = myLooper(); |
| 82 | + if (me == null) { |
| 83 | + throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); |
| 84 | + } |
| 85 | + final MessageQueue queue = me.mQueue; |
| 86 | + |
| 87 | + // Make sure the identity of this thread is that of the local process, |
| 88 | + // and keep track of what that identity token actually is. |
| 89 | + Binder.clearCallingIdentity(); |
| 90 | + final long ident = Binder.clearCallingIdentity(); |
| 91 | + // 此处死循环来从队列里面取消息 |
| 92 | + for (;;) { |
| 93 | + Message msg = queue.next(); // might block |
| 94 | + if (msg == null) { |
| 95 | + // No message indicates that the message queue is quitting. |
| 96 | + // 如果是空,说明正在退出 |
| 97 | + return; |
| 98 | + } |
| 99 | + |
| 100 | + // This must be in a local variable, in case a UI event sets the logger |
| 101 | + final Printer logging = me.mLogging; |
| 102 | + if (logging != null) { |
| 103 | + logging.println(">>>>> Dispatching to " + msg.target + " " + |
| 104 | + msg.callback + ": " + msg.what); |
| 105 | + } |
| 106 | + // Make sure the observer won't change while processing a transaction. |
| 107 | + final Observer observer = sObserver; |
| 108 | + |
| 109 | + final long traceTag = me.mTraceTag; |
| 110 | + long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs; |
| 111 | + long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs; |
| 112 | + if (thresholdOverride > 0) { |
| 113 | + slowDispatchThresholdMs = thresholdOverride; |
| 114 | + slowDeliveryThresholdMs = thresholdOverride; |
| 115 | + } |
| 116 | + final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0); |
| 117 | + final boolean logSlowDispatch = (slowDispatchThresholdMs > 0); |
| 118 | + |
| 119 | + final boolean needStartTime = logSlowDelivery || logSlowDispatch; |
| 120 | + final boolean needEndTime = logSlowDispatch; |
| 121 | + |
| 122 | + if (traceTag != 0 && Trace.isTagEnabled(traceTag)) { |
| 123 | + Trace.traceBegin(traceTag, msg.target.getTraceName(msg)); |
| 124 | + } |
| 125 | + |
| 126 | + final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0; |
| 127 | + final long dispatchEnd; |
| 128 | + Object token = null; |
| 129 | + if (observer != null) { |
| 130 | + token = observer.messageDispatchStarting(); |
| 131 | + } |
| 132 | + long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid); |
| 133 | + try { |
| 134 | + // 最关键的地方,这里就是调用message的handler来处理这个消息。 |
| 135 | + msg.target.dispatchMessage(msg); |
| 136 | + if (observer != null) { |
| 137 | + observer.messageDispatched(token, msg); |
| 138 | + } |
| 139 | + dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0; |
| 140 | + } catch (Exception exception) { |
| 141 | + if (observer != null) { |
| 142 | + observer.dispatchingThrewException(token, msg, exception); |
| 143 | + } |
| 144 | + throw exception; |
| 145 | + } finally { |
| 146 | + ThreadLocalWorkSource.restore(origWorkSource); |
| 147 | + if (traceTag != 0) { |
| 148 | + Trace.traceEnd(traceTag); |
| 149 | + } |
| 150 | + } |
| 151 | + |
| 152 | + |
| 153 | + // Make sure that during the course of dispatching the |
| 154 | + // identity of the thread wasn't corrupted. |
| 155 | + final long newIdent = Binder.clearCallingIdentity(); |
| 156 | + if (ident != newIdent) { |
| 157 | + Log.wtf(TAG, "Thread identity changed from 0x" |
| 158 | + + Long.toHexString(ident) + " to 0x" |
| 159 | + + Long.toHexString(newIdent) + " while dispatching to " |
| 160 | + + msg.target.getClass().getName() + " " |
| 161 | + + msg.callback + " what=" + msg.what); |
| 162 | + } |
| 163 | + |
| 164 | + msg.recycleUnchecked(); |
| 165 | + } |
| 166 | + } |
| 167 | +``` |
| 168 | + |
| 169 | +OK, 了解到了Looper会把Message分给Handler来做,那么来继续看Handler里面的`dispatchMessage(Message)`这个方法。 |
| 170 | + |
| 171 | +```java |
| 172 | +public void dispatchMessage(@NonNull Message msg) { |
| 173 | + if (msg.callback != null) { |
| 174 | + handleCallback(msg); |
| 175 | + } else { |
| 176 | + if (mCallback != null) { |
| 177 | + if (mCallback.handleMessage(msg)) { |
| 178 | + return; |
| 179 | + } |
| 180 | + } |
| 181 | + handleMessage(msg); |
| 182 | + } |
| 183 | + } |
| 184 | +``` |
| 185 | + |
| 186 | +可以看到,这里的分发策略是: |
| 187 | + |
| 188 | +:arrow_right:`Message.Callback`对象是否为空 |
| 189 | + |
| 190 | + 在不为空的情况下,交由这个callback来处理,因此优先级较高 |
| 191 | + |
| 192 | +:arrow_right:`Handler.mCallback` |
| 193 | + |
| 194 | + 在不为空的情况下,交由这个callback来处理,优先级其次 |
| 195 | + |
| 196 | +:arrow_right:`handleMessage(Message)` |
| 197 | + |
| 198 | + 当上述条件都不满足的时候,调用它来处理。(通常,如果我们写一个子类来继承`Handler`类的话,你是需要重载这个方法的) |
| 199 | + |
| 200 | +所以,`Handler`的扩展子类可以重载`dispatchMessage(Message)`这个方法,或者直接重载`handleMessage(message)`这个方法。具体情况,应该根据项目实际需求来走。 |
| 201 | + |
| 202 | + |
| 203 | + |
| 204 | +--- |
| 205 | + |
| 206 | + |
| 207 | + |
| 208 | +#### 进一步分析 |
| 209 | + |
| 210 | +看完上述代码之后,`Handler`这个哥们可能会让你疑惑,会有这么一个循环: |
| 211 | + |
| 212 | +`Handler`:arrow_right:`MessageQueue`:arrow_right:`Message`:arrow_right:`Handler` |
| 213 | + |
| 214 | +即: |
| 215 | + |
| 216 | +1. `Handler`把消息放到`MessageQueue`中 |
| 217 | +2. `MessageQueue`的`Message`到`Handler`中 |
| 218 | + |
| 219 | +首先我们来看看`Handler`有哪些发消息的方法: |
| 220 | + |
| 221 | +```java |
| 222 | +// post系列 |
| 223 | +public final boolean post(@NonNull Runnable r); |
| 224 | +public final boolean postAtTime(@NonNull Runnable r, long uptimeMillis); |
| 225 | +public final boolean postAtTime(@NonNull Runnable r, @Nullable Object token, long uptimeMillis); |
| 226 | +public final boolean postDelayed(@NonNull Runnable r, long delayMillis); |
| 227 | +public final boolean postDelayed(@NonNull Runnable r, int what, long delayMillis); |
| 228 | +public final boolean postDelayed(@NonNull Runnable r, Object token, long delayMillis); |
| 229 | +public final boolean postAtFrontOfQueue(@NonNull Runnable r); |
| 230 | + |
| 231 | +// send系列 |
| 232 | +public final boolean sendMessage(@NonNull Message msg); |
| 233 | +public final boolean sendEmptyMessage(int what); |
| 234 | +public final boolean sendEmptyMessageDelayed(int what, long delayMillis); |
| 235 | +public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis); |
| 236 | +public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis); |
| 237 | +public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis); |
| 238 | +public final boolean sendMessageAtFrontOfQueue(@NonNull Message msg); |
| 239 | + |
| 240 | +``` |
| 241 | + |
| 242 | +这两个系列的方法都可以把`Message`放到`MessageQueue`中。不同的是,send系列参数都直接是`Message`, 而post系列参数都是`Runnable`,因此多了一步中间转换过程,然后再调用send系列的函数进行入队。 |
| 243 | + |
| 244 | +我们挑一个最简单的post系列函数,来分析一下源码: |
| 245 | + |
| 246 | +```java |
| 247 | +public final boolean post(Runnable r) { |
| 248 | + return sendMessageDelayed(getPostMessage(r), 0); |
| 249 | +} |
| 250 | +``` |
| 251 | + |
| 252 | +可以发现,这里调用了一个函数`getPostMessage(Runnable)`来封装出一个`Message`,接着调用send系列的函数来入队: |
| 253 | + |
| 254 | +```java |
| 255 | +private static Message getPostMessage(Runnable r) { |
| 256 | + Message m = Message.obtain(); // 1 |
| 257 | + m.callback = r; // 2 |
| 258 | + return m; |
| 259 | + } |
| 260 | +``` |
| 261 | + |
| 262 | +在代码1处,Android会维护一个全局的Message池,当用户需要使用Message的时候,可以直接通过obtain方法获得。这样的设计是避免不必要的资源浪费。 |
| 263 | + |
| 264 | +代码2处的直接把当前的runnable对象设置成回调函数。 |
| 265 | + |
| 266 | +当准备好Message之后,系统就会调用`sendMessageDelayed`方法来发送消息。这个函数可以设定多长时间的延迟再发送消息,内部的处理是通过当前时间+延迟时间算出该在哪个时间点发送(`sendMessageAtTime)` |
| 267 | + |
| 268 | +```java |
| 269 | +public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) { |
| 270 | + if (delayMillis < 0) { |
| 271 | + delayMillis = 0; |
| 272 | + } |
| 273 | + return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); |
| 274 | +} |
| 275 | +``` |
| 276 | + |
| 277 | +```java |
| 278 | +public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) { |
| 279 | + MessageQueue queue = mQueue; |
| 280 | + if (queue == null) { |
| 281 | + RuntimeException e = new RuntimeException( |
| 282 | + this + " sendMessageAtTime() called with no mQueue"); |
| 283 | + Log.w("Looper", e.getMessage(), e); |
| 284 | + return false; |
| 285 | + } |
| 286 | + return enqueueMessage(queue, msg, uptimeMillis); // 这里就是入队 |
| 287 | + } |
| 288 | +``` |
| 289 | + |
| 290 | +看到这里,我们会有一个疑问,为什么要大费周章,先把`Message` 放到`MessageQueue`里面,最后还是由`Handler`来处理呢? |
| 291 | + |
| 292 | + |
| 293 | + |
| 294 | +--- |
| 295 | + |
| 296 | +#### 继续分析 |
| 297 | + |
| 298 | +上面设计哲学个人认为是有序性。 |
| 299 | + |
| 300 | +当你在主线程发送一个计算量特别大的任务的时候,如果你马上来处理这个任务,主线程就卡死了。那么交由子线程来计算,当它计算好了之后,发个消息告诉主线程,可以了。这样既不会影响主线程的交互(通常把UI线程称为主线程),计算任务又得以进行。 |
| 301 | + |
| 302 | +#### MessageQueue分析 |
| 303 | + |
| 304 | +MessageQueue的分析可能需要你具有一定的JNI知识。因此这里不会过多深入的分析。 |
| 305 | + |
| 306 | +简单看看源码,它有这么一些操作: |
| 307 | + |
| 308 | +- 新建队列 |
| 309 | + |
| 310 | + 由一个本地方法(native方法)`nativeInit()`来创建完成,这个函数返回一个`long`类型的值。这个操作由指针操作完成,具体分析JNI的时候可以再回头看。 |
| 311 | + |
| 312 | +- 元素入队 |
| 313 | + |
| 314 | + `boolean enqueueMessage(Message msg, long when)` |
| 315 | + |
| 316 | +- 元素出队 |
| 317 | + |
| 318 | + `Message next()` |
| 319 | + |
| 320 | +- 删除元素 |
| 321 | + |
| 322 | + `void removeMessages(Handler h, int what, Object obj)` |
| 323 | + |
| 324 | + `void removeMessages(Handler h, Runnable r, Object obj)` |
| 325 | + |
| 326 | +- 销毁队列 |
| 327 | + |
| 328 | + 销毁队列也是一个本地方法完成的,`nativeDestroy()`。实质上,这个东西根所学的队列没有本质区别,因此不做过多赘述,有相关的需求可以回顾数据结构。 |
| 329 | + |
| 330 | + |
| 331 | + |
| 332 | +#### Looper分析 |
| 333 | + |
| 334 | +这个哥们比较有意思了。Looper有点像发动机的意思--它才会推动消息的处理。 |
| 335 | + |
| 336 | +应用程序使用Looper分两种情况, |
| 337 | + |
| 338 | +:arrow_right_hook:主线程(MainThread,也是AcitivtyThread) |
| 339 | + |
| 340 | +:arrow_right_hook:普通线程 |
| 341 | + |
| 342 | +我们看一下普通线程的用法: |
| 343 | + |
| 344 | +```java |
| 345 | +class MyLooperThread extends Thread { |
| 346 | + public Handler mhandler; // 谁干活? |
| 347 | + |
| 348 | + @Override |
| 349 | + public void run() { |
| 350 | + Looper.prepare(); // 1 |
| 351 | + mHandler = new Handler() { |
| 352 | + public void handleMessage() { |
| 353 | + // 这里就是前文中处理消息的地方!!! |
| 354 | + } |
| 355 | + }; |
| 356 | + Looper.loop(); // 2 |
| 357 | + } |
| 358 | +} |
| 359 | +``` |
| 360 | + |
| 361 | +我们发现这里有三个步骤: |
| 362 | + |
| 363 | +1. 调用Looper的`prepare()`方法; |
| 364 | +2. 创建Handler; |
| 365 | +3. Looper开始运作; |
| 366 | + |
| 367 | +可以看到,我们没有发现有Looper对象的创建,最后也是一句Looper.loop,整个消息循环系统就跑起来了。 |
| 368 | + |
| 369 | + |
| 370 | + |
| 371 | + |
| 372 | + |
0 commit comments