Android Handler揭秘(二)

简述:

继续Android Handler揭秘(一),这里来继续分析MessageQueue。

相关代码:

  1. frameworks/base/core/java/android/os/MessageQueue.java
  2. frameworks/base/core/jni/android_os_MessageQueue.cpp
  3. frameworks/base/core/java/android/os/Message.java

正文:

先写个test代码,然后根据test代码来分析代码。

01    public void test3() {
02        Log.d(TAG, "test3 start-->");
03        HandlerThread handlerThread = new HandlerThread("Test3");
04        handlerThread.start();
05        Handler handler = new Handler(handlerThread.getLooper()) {
06            @Override
07            public void handleMessage(Message msg) {
08                Log.d(TAG, "test3 handleMessage msg=" + msg + " Time=" + SystemClock.uptimeMillis());
09            }
10        };
11        Message msg = handler.obtainMessage(0, 0, 0, "msg");
12        handler.sendMessageDelayed(msg, 3000);
13        Log.d(TAG, "test3 send Msg0=" + msg + " Time=" + SystemClock.uptimeMillis());
14        msg = handler.obtainMessage(1, 0, 0, "msg1");
15        handler.sendMessageDelayed(msg, 6000);
16        Log.d(TAG, "test3 send Msg1=" + msg + " Time=" + SystemClock.uptimeMillis());
17        Log.d(TAG, "test3 end<--");
18    }

log输出:

2019-01-07 15:18:08.861 5819-5819/com.fy.platfromdebug D/TestHandler: test3 start-->
2019-01-07 15:18:08.865 5819-5819/com.fy.platfromdebug D/TestHandler: test3 send Msg0={ when=+3s0ms what=0 obj=msg target=com.fy.platfromdebug.TestHandler$1 } Time=177966090
2019-01-07 15:18:08.866 5819-5819/com.fy.platfromdebug D/TestHandler: test3 send Msg1={ when=+6s0ms what=1 obj=msg1 target=com.fy.platfromdebug.TestHandler$1 } Time=177966090
2019-01-07 15:18:08.867 5819-5819/com.fy.platfromdebug D/TestHandler: test3 end<--
2019-01-07 15:18:11.866 5819-5851/com.fy.platfromdebug D/TestHandler: test3 handleMessage msg={ when=-1ms what=0 obj=msg target=com.fy.platfromdebug.TestHandler$1 } Time=177969091
2019-01-07 15:18:14.869 5819-5851/com.fy.platfromdebug D/TestHandler: test3 handleMessage msg={ when=-4ms what=1 obj=msg1 target=com.fy.platfromdebug.TestHandler$1 } Time=177972094

从第11行开始分析,msg并不是写成直接Message msg = new Message(),原因是Message里面有做对象回收池(pool of recycled objects),有利于节省内存。handler.obtainMessage最终会调用到:

frameworks/base/core/java/android/os/Message.java

242      /**
243       * Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>,
244       * <em>arg1</em>, <em>arg2</em>, and <em>obj</em> members.
245       *
246       * @param h  The <em>target</em> value to set.
247       * @param what  The <em>what</em> value to set.
248       * @param arg1  The <em>arg1</em> value to set.
249       * @param arg2  The <em>arg2</em> value to set.
250       * @param obj  The <em>obj</em> value to set.
251       * @return  A Message object from the global pool.
252       */
253      public static Message obtain(Handler h, int what,
254              int arg1, int arg2, Object obj) {
255          Message m = obtain();
256          m.target = h;
257          m.what = what;
258          m.arg1 = arg1;
259          m.arg2 = arg2;
260          m.obj = obj;
261  
262          return m;
263      }

缓存的关键就在于255 行Message m = obtain();

frameworks/base/core/java/android/os/Message.java

122      /**
123       * Return a new Message instance from the global pool. Allows us to
124       * avoid allocating new objects in many cases.
125       */
126      public static Message obtain() {
127          synchronized (sPoolSync) {
128              if (sPool != null) {
129                  Message m = sPool;
130                  sPool = m.next;
131                  m.next = null;
132                  m.flags = 0; // clear in-use flag
133                  sPoolSize--;
134                  return m;
135              }
136          }
137          return new Message();
138      }

加上下面的方法,就可以知道缓存的工作原理了。

frameworks/base/core/java/android/os/Message.java

291      /**
292       * Recycles a Message that may be in-use.
293       * Used internally by the MessageQueue and Looper when disposing of queued Messages.
294       */
295      void recycleUnchecked() {
296          // Mark the message as in use while it remains in the recycled object pool.
297          // Clear out all other details.
298          flags = FLAG_IN_USE;
299          what = 0;
300          arg1 = 0;
301          arg2 = 0;
302          obj = null;
303          replyTo = null;
304          sendingUid = -1;
305          when = 0;
306          target = null;
307          callback = null;
308          data = null;
309  
310          synchronized (sPoolSync) {
311              if (sPoolSize < MAX_POOL_SIZE) {
312                  next = sPool;
313                  sPool = this;
314                  sPoolSize++;
315              }
316          }
317      }

当有Message不再有用的时候,清空成员的值,然后判断下,当前对象回收池里面存的个数,如果小于MAX_POOL_SIZE,就将这个Message插入sPool链表,这样这个对象会被引用起来,系统不会回收,同时sPoolSize加1。

当我们需要新建一个Message时,通过public static Message obtain()方法,从sPool链表里面取出一个Message(如果sPool链表里面没有时才new一个Message),同时对sPoolSize减1。

这里的链表操作都是有加锁同步,确保多线程操作不会有问题。

 

分析完Message链表缓存机制。回到test3代码第12行handler.sendMessageDelayed(msg, 3000),此函数最终调用至

frameworks/base/core/java/android/os/MessageQueue.java

536      boolean enqueueMessage(Message msg, long when) {
            //异常判断
537          if (msg.target == null) {
538              throw new IllegalArgumentException("Message must have a target.");
539          }
540          if (msg.isInUse()) {
541              throw new IllegalStateException(msg + " This message is already in use.");
542          }
543  
             //加锁同步
544          synchronized (this) {
545              if (mQuitting) {
546                  IllegalStateException e = new IllegalStateException(
547                          msg.target + " sending message to a Handler on a dead thread");
548                  Log.w(TAG, e.getMessage(), e);
549                  msg.recycle();
550                  return false;
551              }
552  
553              msg.markInUse();//标记使用
554              msg.when = when;
555              Message p = mMessages;
556              boolean needWake;
557              if (p == null || when == 0 || when < p.when) {//链表为空或者时间小于链表第一个消息,将消息插入链表第一个
558                  // New head, wake up the event queue if blocked.
559                  msg.next = p;
560                  mMessages = msg;
561                  needWake = mBlocked;
562              } else {//将消息按when来插入合适的位置
563                  // Inserted within the middle of the queue.  Usually we don't have to wake
564                  // up the event queue unless there is a barrier at the head of the queue
565                  // and the message is the earliest asynchronous message in the queue.
566                  needWake = mBlocked && p.target == null && msg.isAsynchronous();
567                  Message prev;
568                  for (;;) {
569                      prev = p;
570                      p = p.next;
571                      if (p == null || when < p.when) {
572                          break;
573                      }
574                      if (needWake && p.isAsynchronous()) {
575                          needWake = false;
576                      }
577                  }
578                  msg.next = p; // invariant: p == prev.next
579                  prev.next = msg;
580              }
581  
582              // We can assume mPtr != 0 because mQuitting is false.
583              if (needWake) {//mBlocked在next方法里面设值,其实就是当前线程处理等待的时候,才需要唤醒
584                  nativeWake(mPtr);
585              }
586          }
587          return true;
588      }

逻辑很简单,如果当前MessageQueue的mMessages是否有过链表,如果没有,就把链表设置为参数msg。如果有,就根据msg的触发时间when插入mMessages链表。这里有个needWake,根据mBlocked等条件来判断是否需要调用nativeWake。到这里,我们看到了native调用。其实MessageQueue实例化的时候就调用了nativeInit,且后再提。先来看看这里的mBlocked变量被改的方法next()(next方法是被Looper.loop()方法循环里面调用的)。


Tips:

  1. next方法是被Looper.loop()方法循环里面调用的。
  2. Message有个成员变量 Message next,然后再加上MessageQueue的mMessages prev,就是一个链表了。

frameworks/base/core/java/android/os/MessageQueue.java

310      Message next() {
311          // Return here if the message loop has already quit and been disposed.
312          // This can happen if the application tries to restart a looper after quit
313          // which is not supported.
314          final long ptr = mPtr;//mPtr是持有的native层的NativeMessageQueue对象
315          if (ptr == 0) {
316              return null;
317          }
318  
319          int pendingIdleHandlerCount = -1; // -1 only during first iteration
320          int nextPollTimeoutMillis = 0;
321          for (;;) {
322              if (nextPollTimeoutMillis != 0) {
323                  Binder.flushPendingCommands();
324              }
325  
                //实际上是调用Looper.cpp里面的pollOnce,基于linux的epoll,后续详细分析
326              nativePollOnce(ptr, nextPollTimeoutMillis);
327  
328              synchronized (this) {
329                  // Try to retrieve the next message.  Return if found.
330                  final long now = SystemClock.uptimeMillis();
331                  Message prevMsg = null;
332                  Message msg = mMessages;
333                  if (msg != null && msg.target == null) {//当前是屏障状态,跟android的vsync刷新机制有关系
334                      // Stalled by a barrier.  Find the next asynchronous message in the queue.
335                      do {//过滤掉不是异步处理的msg
336                          prevMsg = msg;
337                          msg = msg.next;
338                      } while (msg != null && !msg.isAsynchronous());
339                  }
340                  if (msg != null) {
341                      if (now < msg.when) {//当前消息时间嗨没到,设置nextPollTimeoutMillis,然后通知native去pollOnce等待
342                          // Next message is not ready.  Set a timeout to wake up when it is ready.
343                          nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
344                      } else {//时间已经到,返回消息给Looper进行分发处理
345                          // Got a message.
346                          mBlocked = false;
347                          if (prevMsg != null) {
348                              prevMsg.next = msg.next;
349                          } else {
350                              mMessages = msg.next;
351                          }
352                          msg.next = null;
353                          if (DEBUG) Log.v(TAG, "Returning message: " + msg);
354                          msg.markInUse();
355                          return msg;
356                      }
357                  } else {
358                      // No more messages.
359                      nextPollTimeoutMillis = -1;
360                  }
361  
362                  // Process the quit message now that all pending messages have been handled.
363                  if (mQuitting) {
364                      dispose();
365                      return null;
366                  }
367  
            //下面的用于mIdleHandlers状态的一些处理,比如GC
368                  // If first time idle, then get the number of idlers to run.
369                  // Idle handles only run if the queue is empty or if the first message
370                  // in the queue (possibly a barrier) is due to be handled in the future.
371                  if (pendingIdleHandlerCount < 0
372                          && (mMessages == null || now < mMessages.when)) {
373                      pendingIdleHandlerCount = mIdleHandlers.size();
374                  }
375                  if (pendingIdleHandlerCount <= 0) {
376                      // No idle handlers to run.  Loop and wait some more.
377                      mBlocked = true;//标记下次enqueueMessage的时候,需要唤醒
378                      continue;
379                  }
380  
381                  if (mPendingIdleHandlers == null) {
382                      mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
383                  }
384                  mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
385              }
386  
387              // Run the idle handlers.
388              // We only ever reach this code block during the first iteration.
389              for (int i = 0; i < pendingIdleHandlerCount; i++) {
390                  final IdleHandler idler = mPendingIdleHandlers[i];
391                  mPendingIdleHandlers[i] = null; // release the reference to the handler
392  
393                  boolean keep = false;
394                  try {
395                      keep = idler.queueIdle();
396                  } catch (Throwable t) {
397                      Log.wtf(TAG, "IdleHandler threw exception", t);
398                  }
399  
400                  if (!keep) {
401                      synchronized (this) {
402                          mIdleHandlers.remove(idler);
403                      }
404                  }
405              }
406  
407              // Reset the idle handler count to 0 so we do not run them again.
408              pendingIdleHandlerCount = 0;
409  
410              // While calling an idle handler, a new message could have been delivered
411              // so go back and look again for a pending message without waiting.
412              nextPollTimeoutMillis = 0;
413          }
414      }

最后来看下Looper调用MessageQueue的next方法的地方,Looper.loop(),去掉了一些计算分发时间代码。

frameworks/base/core/java/android/os/Looper.java
 /**
134       * Run the message queue in this thread. Be sure to call
135       * {@link #quit()} to end the loop.
136       */
137      public static void loop() {
138          final Looper me = myLooper();
139          if (me == null) {
140              throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
141          }
142          final MessageQueue queue = me.mQueue;//取出链表
143  
144          // Make sure the identity of this thread is that of the local process,
145          // and keep track of what that identity token actually is.
146          Binder.clearCallingIdentity();
147          final long ident = Binder.clearCallingIdentity();
148  
            ...
158  
159          for (;;) {
                 //这里取出消息,如果消息时间未到,会被block
160              Message msg = queue.next(); // might block
161              if (msg == null) {
162                  // No message indicates that the message queue is quitting.
163                  return;
164              }
165  
            ...
                 //分发处理消息,调用msg的handler处理消息,最终回调callback/override的handleMessage(msg),对应到test代码就是07行的handleMessage
192              try {
193                  msg.target.dispatchMessage(msg);
194                  dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
195              } finally {
196                  if (traceTag != 0) {
197                      Trace.traceEnd(traceTag);
198                  }
199              }
            ...

222              // Make sure that during the course of dispatching the
223              // identity of the thread wasn't corrupted.
224              final long newIdent = Binder.clearCallingIdentity();
225              if (ident != newIdent) {
226                  Log.wtf(TAG, "Thread identity changed from 0x"
227                          + Long.toHexString(ident) + " to 0x"
228                          + Long.toHexString(newIdent) + " while dispatching to "
229                          + msg.target.getClass().getName() + " "
230                          + msg.callback + " what=" + msg.what);
231              }
232  
233              msg.recycleUnchecked();//消息recycle,是否真正的GC回收了,前面有讲述
234          }
235      }

到这里,消息分发处理的逻辑都走完。

但是中间有略去native层的业务,线程阻塞、线程唤醒、native层的MessageQueue等,请见下回讲解。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值