Handle是进程内部, 线程之间的通信机制.
handle主要接受子线程发送的数据, 并用此数据配合主线程更新UI
handle可以分发Message对象和Runnable对象到主线程中, 每个handle实例, 都会绑定到创建他的线程中, 它有两个作用,:
(1) 安排消息在某个主线程中某个地方执行
(2) 安排一个动作在不同的线程中执行
Handle, Lopper, MessegeQueue, Message的关系
handle机制中, 主要牵涉的类有如下四个, 它们分工明确, 但又互相作用
1. Message:消息
2. hanlder:消息的发起者
3. Lopper: 消息的遍历者
4.MessageQueue 消息队列
1.Loop类
public final class Looper {@UnsupportedAppUsagestatic final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();@UnsupportedAppUsageprivate static Looper sMainLooper; // guarded by Looper.classprivate static Observer sObserver;@UnsupportedAppUsagefinal MessageQueue mQueue;final Thread mThread;private boolean mInLoop;266 public static void loop() {
267 final Looper me = myLooper();
268 if (me == null) {
269 throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
270 }
271 if (me.mInLoop) {
272 Slog.w(TAG, "Loop again would have the queued messages be executed"
273 + " before this one completed.");
274 }
275
276 me.mInLoop = true;
277
278 // Make sure the identity of this thread is that of the local process,
279 // and keep track of what that identity token actually is.
280 Binder.clearCallingIdentity();
281 final long ident = Binder.clearCallingIdentity();
282
283 // Allow overriding a threshold with a system prop. e.g.
284 // adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
285 final int thresholdOverride =
286 SystemProperties.getInt("log.looper."
287 + Process.myUid() + "."
288 + Thread.currentThread().getName()
289 + ".slow", -1);
290
291 me.mSlowDeliveryDetected = false;
292
293 for (;;) {
294 if (!loopOnce(me, ident, thresholdOverride)) {
295 return;
296 }
297 }
298 }330 private Looper(boolean quitAllowed) {
331 mQueue = new MessageQueue(quitAllowed);
332 mThread = Thread.currentThread();
333 }
创建Looper对象的时候,同时创建了MessageQueue,并让Looper绑定当前线程。但我们从来不直接调用构造方法获取Looper对象,而是使用Looper的prepare()方法
108 public static void prepare() {
109 prepare(true);
110 }
111
112 private static void prepare(boolean quitAllowed) {
113 if (sThreadLocal.get() != null) {
114 throw new RuntimeException("Only one Looper may be created per thread");
115 }
116 sThreadLocal.set(new Looper(quitAllowed));
117 }
118 126 @Deprecated
127 public static void prepareMainLooper() {
128 prepare(false);
129 synchronized (Looper.class) {
130 if (sMainLooper != null) {
131 throw new IllegalStateException("The main Looper has already been prepared.");
132 }
133 sMainLooper = myLooper();
134 }
135 }
prepare()使用ThreadLocal 保存当前Looper对象,ThreadLocal 类可以对数据进行线程隔离,保证了在当前线程只能获取当前线程的Looper对象,同时prepare()保证当前线程有且只有一个Looper对象,间接保证了一个线程只有一个MessageQueue对象
prepareMainLooper统在启动App时,已经帮我们调用了
266 public static void loop() {
267 final Looper me = myLooper();
268 if (me == null) {
269 throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
270 }
271 if (me.mInLoop) {
272 Slog.w(TAG, "Loop again would have the queued messages be executed"
273 + " before this one completed.");
274 }
275
276 me.mInLoop = true;
277
278 // Make sure the identity of this thread is that of the local process,
279 // and keep track of what that identity token actually is.
280 Binder.clearCallingIdentity();
281 final long ident = Binder.clearCallingIdentity();
282
283 // Allow overriding a threshold with a system prop. e.g.
284 // adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
285 final int thresholdOverride =
286 SystemProperties.getInt("log.looper."
287 + Process.myUid() + "."
288 + Thread.currentThread().getName()
289 + ".slow", -1);
290
291 me.mSlowDeliveryDetected = false;
292
293 for (;;) {
294 if (!loopOnce(me, ident, thresholdOverride)) {
295 return;
296 }
297 }
298 }
Lopper通过loop()开启无限循环,通过MessageQueue的next()获取message对象。一旦获取就调用msg.target.dispatchMEssage(msg)将msg交给handler对象处理(msg.target是handler对象)
所以Looper.loop的作用就是:从当前线程的MessageQueue从不断取出Message,并调用其相关的回调方法。
2. handler类
-
创建Handler对象
-
得到当前线程的Looper对象,并判断是否为空
-
让创建的Handler对象持有Looper、MessageQueu、Callback的引用
214 public Handler(@Nullable Callback callback, boolean async) { 215 if (FIND_POTENTIAL_LEAKS) { 216 final Class<? extends Handler> klass = getClass(); 217 if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && 218 (klass.getModifiers() & Modifier.STATIC) == 0) { 219 Log.w(TAG, "The following Handler class should be static or leaks might occur: " + 220 klass.getCanonicalName()); 221 } 222 } 223 224 mLooper = Looper.myLooper(); 225 if (mLooper == null) { 226 throw new RuntimeException( 227 "Can't create handler inside thread " + Thread.currentThread() 228 + " that has not called Looper.prepare()"); 229 } 230 mQueue = mLooper.mQueue; 231 mCallback = callback; 232 mAsynchronous = async; 233 mIsShared = false; 234 } 235
使用Handler发送消息主要有两种,一种是sendXXXMessage方式,还有一个postXXX方式,不过两种方式最后都会调用到sendMessageDelayed方法
下面为sendMessage方式
发送消息,将消息插入队列:sendMessage->sendMessageDelayed->sendMessageAtTime->enqueueMessage,这里会决定message是否为同步消息或者异步消息
-
727 public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) { 728 MessageQueue queue = mQueue; 729 if (queue == null) { 730 RuntimeException e = new RuntimeException( 731 this + " sendMessageAtTime() called with no mQueue"); 732 Log.w("Looper", e.getMessage(), e); 733 return false; 734 } 735 return enqueueMessage(queue, msg, uptimeMillis); 736 }
778 private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg, 779 long uptimeMillis) { 780 msg.target = this; 781 msg.workSourceUid = ThreadLocalWorkSource.getUid(); 782 783 if (mAsynchronous) { 784 msg.setAsynchronous(true); 785 } 786 return queue.enqueueMessage(msg, uptimeMillis); 787 }
549 boolean enqueueMessage(Message msg, long when) { 550 if (msg.target == null) { 551 throw new IllegalArgumentException("Message must have a target."); 552 } 553 554 synchronized (this) { // 一个message只能呢个发送一次 555 if (msg.isInUse()) { 556 throw new IllegalStateException(msg + " This message is already in use."); 557 } 558 559 if (mQuitting) { 560 IllegalStateException e = new IllegalStateException( 561 msg.target + " sending message to a Handler on a dead thread"); 562 Log.w(TAG, e.getMessage(), e); 563 msg.recycle(); 564 return false; 565 } 566 // 标记message已经使用 567 msg.markInUse(); 568 msg.when = when; // 拿到头部 569 Message p = mMessages; 570 boolean needWake; 571 if (p == null || when == 0 || when < p.when) { 572 // New head, wake up the event queue if blocked. // 将消息插入到头部, 指向刚才拿到的消息 573 msg.next = p; 574 mMessages = msg; 575 needWake = mBlocked; 576 } else { // 根据需要把消息插入到消息队列的合适位置,通常是调用xxxDelay方法,延时发送消息 577 // Inserted within the middle of the queue. Usually we don't have to wake 578 // up the event queue unless there is a barrier at the head of the queue 579 // and the message is the earliest asynchronous message in the queue. 580 needWake = mBlocked && p.target == null && msg.isAsynchronous(); 581 Message prev; 582 for (;;) { 583 prev = p; 584 p = p.next; 585 if (p == null || when < p.when) { 586 break; 587 } 588 if (needWake && p.isAsynchronous()) { 589 needWake = false; 590 } 591 } 592 msg.next = p; // invariant: p == prev.next 593 prev.next = msg; 594 } 595 596 // We can assume mPtr != 0 because mQuitting is false. 597 if (needWake) { 598 nativeWake(mPtr); 599 } 600 } 601 return true; 602 }
//getPostMessage方法是两种发送消息的不同之处
Post这个方法我们发现也是将我们传入的参数封装成了一个消息,只是这次是m.callback = r,刚才是msg.what=what,至于Message的这些属性就不看了
434 public final boolean post(@NonNull Runnable r) { 435 return sendMessageDelayed(getPostMessage(r), 0); 436 }943 private static Message getPostMessage(Runnable r) { 944 Message m = Message.obtain(); 945 m.callback = r; 946 return m; 947 }
post方法只是先调用了getPostMessage方法,用Runnable去封装一个Message,然后就调用了sendMessageDelayed,把封装的Message加入到MessageQueue中。
所以使用handler发送消息的本质都是:把Message加入到Handler中的MessageQueue中去
97 public void dispatchMessage(@NonNull Message msg) { 98 if (msg.callback != null) { 99 handleCallback(msg); 100 } else { 101 if (mCallback != null) { 102 if (mCallback.handleMessage(msg)) { 103 return; 104 } 105 } 106 handleMessage(msg); 107 } 108 } 109
可以看出,这个方法就是从MessageQueue中取出Message以后,进行分发处理。
首先,判断msg.callback是不是空,其实msg.callback是一个Runnable对象,是Handler.post方式传递进来的参数。而hanldeCallback就是调用的Runnable的run方法。
然后,判断mCallback是否为空,这是一个Handler.Callback的接口类型,之前说了Handler有多个构造方法,可以提供设置Callback,如果这里不为空,则调用它的hanldeMessage方法,注意,这个方法有返回值,如果返回了true,表示已经处理 ,不再调用Handler的handleMessage方法;如果mCallback为空,或者不为空但是它的handleMessage返回了false,则会继续调用Handler的handleMessage方法,该方法就是我们经常重写的那个方法。
3. MessageQueue
-
318 @UnsupportedAppUsage 319 Message next() { 320 // Return here if the message loop has already quit and been disposed. 321 // This can happen if the application tries to restart a looper after quit 322 // which is not supported. 323 final long ptr = mPtr; 324 if (ptr == 0) { 325 return null; 326 } 327 328 int pendingIdleHandlerCount = -1; // -1 only during first iteration 329 int nextPollTimeoutMillis = 0; 330 for (;;) { 331 if (nextPollTimeoutMillis != 0) { 332 Binder.flushPendingCommands(); 333 } 334 335 nativePollOnce(ptr, nextPollTimeoutMillis); 336 337 synchronized (this) { 338 // Try to retrieve the next message. Return if found. 339 final long now = SystemClock.uptimeMillis(); 340 Message prevMsg = null; 341 Message msg = mMessages; 342 if (msg != null && msg.target == null) { 343 // Stalled by a barrier. Find the next asynchronous message in the queue. 344 do { 345 prevMsg = msg; 346 msg = msg.next; 347 } while (msg != null && !msg.isAsynchronous()); 348 } 349 if (msg != null) { 350 if (now < msg.when) { 351 // Next message is not ready. Set a timeout to wake up when it is ready. 352 nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE); 353 } else { 354 // Got a message. 355 mBlocked = false; 356 if (prevMsg != null) { 357 prevMsg.next = msg.next; 358 } else { 359 mMessages = msg.next; 360 } 361 msg.next = null; 362 if (DEBUG) Log.v(TAG, "Returning message: " + msg); 363 msg.markInUse(); 364 return msg; 365 } 366 } else { 367 // No more messages. 368 nextPollTimeoutMillis = -1; 369 } 370 371 // Process the quit message now that all pending messages have been handled. 372 if (mQuitting) { 373 dispose(); 374 return null; 375 } 376 377 // If first time idle, then get the number of idlers to run. 378 // Idle handles only run if the queue is empty or if the first message 379 // in the queue (possibly a barrier) is due to be handled in the future. 380 if (pendingIdleHandlerCount < 0 381 && (mMessages == null || now < mMessages.when)) { 382 pendingIdleHandlerCount = mIdleHandlers.size(); 383 } 384 if (pendingIdleHandlerCount <= 0) { 385 // No idle handlers to run. Loop and wait some more. 386 mBlocked = true; 387 continue; 388 } 389 390 if (mPendingIdleHandlers == null) { 391 mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)]; 392 } 393 mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers); 394 } 395 396 // Run the idle handlers. 397 // We only ever reach this code block during the first iteration. 398 for (int i = 0; i < pendingIdleHandlerCount; i++) { 399 final IdleHandler idler = mPendingIdleHandlers[i]; 400 mPendingIdleHandlers[i] = null; // release the reference to the handler 401 402 boolean keep = false; 403 try { 404 keep = idler.queueIdle(); 405 } catch (Throwable t) { 406 Log.wtf(TAG, "IdleHandler threw exception", t); 407 } 408 409 if (!keep) { 410 synchronized (this) { 411 mIdleHandlers.remove(idler); 412 } 413 } 414 } 415 416 // Reset the idle handler count to 0 so we do not run them again. 417 pendingIdleHandlerCount = 0; 418 419 // While calling an idle handler, a new message could have been delivered 420 // so go back and look again for a pending message without waiting. 421 nextPollTimeoutMillis = 0; 422 } 423 }
next方法中,首先设置一个死循环,然后调用nativePollOnce(ptr, nextPollTimeoutMillis)方法,它是一个native方法,用于阻塞MessageQueue,主要是关注它的第二个参数nextPollTimeoutMillis,有如下三种可能:
如果nextPollTimeoutMillis=-1,一直阻塞不会超时。
如果nextPollTimeoutMillis=0,不会阻塞,立即返回。
如果nextPollTimeoutMillis>0,最长阻塞nextPollTimeoutMillis毫秒(超时),如果其间有程序唤醒会立即返回。
我们先继续往下看,开始nextPollTimeoutMillis为0,也就是不会阻塞,则继续往下,这时候有三种情况
1.延时消息,则直接算出目前需要延时的时间nextPollTimeoutMillis,注意,这时候并没有把消息返回,而是继续往下,设置mBlocked为true,表示消息队列已阻塞,并continue执行for循环体,再次执行nativePollOnce方法,这时候nextPollTimeoutMillis>0,则会导致MessageQueue休眠nextPollTimeoutMillis毫秒,接着应该会走到情况2.
2.不是延时消息,则设置mBlocked为false,表示消息队列没有阻塞,直接把消息返回,且把消息出队。
3. 如果消息为空,则调用位置nextPollTimeoutMillis为-1,继续往下,设置mBlocked为true,表示消息队列已阻塞,并continue继续for循环,这时候调用nativePollOnce会一直阻塞,且不会超时。
所以,当消息队列为空时,其实是调用本地方法nativePollOnce,且第二个参数为-1,它会导致当前线程阻塞,且不会超时
4. Message
Message分为3种:普通消息(同步消息)、屏障消息(同步屏障)和异步消息。我们通常使用的都是普通消息,而屏障消息就是在消息队列中插入一个屏障,在屏障之后的所有普通消息都会被挡着,不能被处理。不过异步消息却例外,屏障不会挡住异步消息,
因此可以这样认为:屏障消息就是为了确保异步消息的优先级,设置了屏障后,只能处理其后的异步消息,同步消息会被挡住,除非撤销屏障。
同步屏障是通过MessageQueue的postSyncBarrier方法插入到消息队列的。
屏障消息和普通消息的区别是屏障消息没有tartget。
1.屏障的插队方法
屏障是通过MessageQueue的postSyncBarrier方法插入到消息队列的。
public int postSyncBarrier() {
473 return postSyncBarrier(SystemClock.uptimeMillis());
474 }
475
476 private int postSyncBarrier(long when) {
477 // Enqueue a new sync barrier token.
478 // We don't need to wake the queue because the purpose of a barrier is to stall it.
479 synchronized (this) {
480 final int token = mNextBarrierToken++;
481 final Message msg = Message.obtain();
482 msg.markInUse();
483 msg.when = when;
484 msg.arg1 = token;
485
486 Message prev = null;
487 Message p = mMessages;
488 if (when != 0) {
489 while (p != null && p.when <= when) {
490 prev = p;
491 p = p.next;
492 }
493 }
494 if (prev != null) { // invariant: p == prev.next
495 msg.next = p;
496 prev.next = msg;
497 } else {
498 msg.next = p;
499 mMessages = msg;
500 }
501 return token;
502 }
503 }
504
- 屏障消息和普通消息的区别在于屏障没有tartget,普通消息有target是因为它需要将消息分发给对应的target,而屏障不需要被分发,它就是用来挡住普通消息来保证异步消息优先处理的。
- 屏障和普通消息一样可以根据时间来插入到消息队列中的适当位置,并且只会挡住它后面的同步消息的分发。
- postSyncBarrier返回一个int类型的数值,通过这个数值可以撤销屏障。
- postSyncBarrier方法是私有的,如果我们想调用它就得使用反射。
- 插入普通消息会唤醒消息队列,但是插入屏障不会。
2.屏障的工作原理
通过postSyncBarrier方法屏障就被插入到消息队列中了,那么屏障是如何挡住普通消息只允许异步消息通过的呢?我们知道MessageQueue是通过next方法来获取消息的。
通过messaQequeue中的next(),如果碰到屏障就遍历整个消息链表找到最近的一条异步消息,在遍历的过程中只有异步消息才会被处理执行到 if (msg != null){}中的代码。可以看到通过这种方式就挡住了所有的普通消息
3,同步消息还是异步消息的决定时间
Handler有几个构造方法,可以传入async标志为true,这样构造的Handler发送的消息就是异步消息。不过可以看到,这些构造函数都是hide的,正常我们是不能调用的,不过利用反射机制可以使用@hide方法。
/*** @hide*/
public Handler(boolean async) {}/*** @hide*/
public Handler(Callback callback, boolean async) { }/*** @hide*/
public Handler(Looper looper, Callback callback, boolean async) {}
也可以直接调用message.setAsynchronous(true);来进行设置为异步消息
509 public void setAsynchronous(boolean async) {
510 if (async) {
511 flags |= FLAG_ASYNCHRONOUS;
512 } else {
513 flags &= ~FLAG_ASYNCHRONOUS;
514 }
515 }
3.屏障的移除
移除屏障可以通过MessageQueue的removeSyncBarrier方法:
517 public void removeSyncBarrier(int token) {
518 // Remove a sync barrier token from the queue.
519 // If the queue is no longer stalled by a barrier then wake it.
520 synchronized (this) {
521 Message prev = null;
522 Message p = mMessages;
523 while (p != null && (p.target != null || p.arg1 != token)) {
524 prev = p;
525 p = p.next;
526 }
527 if (p == null) {
528 throw new IllegalStateException("The specified message queue synchronization "
529 + " barrier token has not been posted or has already been removed.");
530 }
531 final boolean needWake;
532 if (prev != null) {
533 prev.next = p.next;
534 needWake = false;
535 } else {
536 mMessages = p.next;
537 needWake = mMessages == null || mMessages.target != null;
538 }
539 p.recycleUnchecked();
540
541 // If the loop is quitting then it is already awake.
542 // We can assume mPtr != 0 when mQuitting is false.
543 if (needWake && !mQuitting) {
544 nativeWake(mPtr);
545 }
546 }
547 }
总结下Handler消息机制主要的四个类的功能
- Message:信息的携带者,持有了Handler,存在MessageQueue中,一个线程可以有多个
- Hanlder:消息的发起者,发送Message以及消息处理的回调实现,一个线程可以有多个Handler对象
- Looper:消息的遍历者,从MessageQueue中循环取出Message进行处理,一个线程最多只有一个
- MessageQueue:消息队列,存放了Handler发送的消息,供Looper循环取消息,一个线程最多只有一个