Android源碼解析Handler系列第(三)篇---深入了解Android的消息機(jī)制

轉(zhuǎn)載請(qǐng)注明文章出處LooperJing!

Android的消息機(jī)制我覺(jué)得是每一個(gè)弄Android開(kāi)發(fā)的人都要弄懂得問(wèn)題,也有很多人對(duì)它進(jìn)行研究,Android的消息機(jī)制的重要性不強(qiáng)調(diào),但是覺(jué)得自己對(duì)Android的消息機(jī)制了解不深刻,所以決定深入源碼,寫(xiě)下三篇博客以記之。因?yàn)镸essage全局池和ThreadLocal對(duì)Android的消息機(jī)制理解很重要,附上前兩篇的博客地址。
Android源碼解析Handler系列第(一)篇 --- Message全局池
Android源碼解析Handler系列第(二)篇 --- ThreadLocal詳解

先來(lái)一張圖感受一下,下面這張圖基本說(shuō)明了Android的消息機(jī)制的工作流程。


Android的消息機(jī)制

不看別的,主要涉及的類(lèi)有Thread,Looper,MessageQueue,Handler,其實(shí)還有一個(gè)ThreadLocal,這些類(lèi)都是整套消息機(jī)制中很關(guān)鍵的類(lèi),下面我們正式分析這套機(jī)制是怎么運(yùn)行的。

要分析這套機(jī)制是怎么運(yùn)行的,要首先從應(yīng)用程序的入口說(shuō)起,Android應(yīng)用程序的入口是ActivityThread類(lèi)的main方法。下面是main方法中的相關(guān)代碼。

 public static void main(String[] args) {
    

        Process.setArgV0("<pre-initialized>");

        //創(chuàng)建UI線(xiàn)程所需要的Looper,Looper有何用,后面再說(shuō)
        Looper.prepareMainLooper();

        //這里最終啟動(dòng)應(yīng)用程序
        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }
        //執(zhí)行消息循環(huán)
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

注意到,入口函數(shù)的最后一行代碼是Looper調(diào)用了靜態(tài)方法Looper. loop(),而這個(gè)loop是死循環(huán),按照正常的理解,在主線(xiàn)程中執(zhí)行死循環(huán),那么就不能做其他任務(wù)了,比如按鈕事件的觸發(fā),動(dòng)畫(huà)的播放等。但是反過(guò)來(lái)想一想,如果這不是死循環(huán),那么最后一行代碼執(zhí)行完,應(yīng)用程序不就跑完了嘛。并且這行代碼也只能放在main的最后一句,如果放在前面,后面的程序就沒(méi)有辦法進(jìn)行了。

好滴, Looper.loop()是執(zhí)行消息循環(huán),去這里看個(gè)究竟。

/**
   * Run the message queue in this thread. Be sure to call
   * {@link #quit()} to end the loop.
   */
  public static void loop() {
      final Looper me = myLooper();
      if (me == null) {
          throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
      }
      final MessageQueue queue = me.mQueue;

      // Make sure the identity of this thread is that of the local process,
      // and keep track of what that identity token actually is.
      Binder.clearCallingIdentity();
      final long ident = Binder.clearCallingIdentity();

      for (;;) {
          Message msg = queue.next(); // might block
          if (msg == null) {
              // No message indicates that the message queue is quitting.
              return;
          }

          // This must be in a local variable, in case a UI event sets the logger
          Printer logging = me.mLogging;
          if (logging != null) {
              logging.println(">>>>> Dispatching to " + msg.target + " " +
                      msg.callback + ": " + msg.what);
          }

          msg.target.dispatchMessage(msg);

          if (logging != null) {
              logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
          }

          // Make sure that during the course of dispatching the
          // identity of the thread wasn't corrupted.
          final long newIdent = Binder.clearCallingIdentity();
          if (ident != newIdent) {
              Log.wtf(TAG, "Thread identity changed from 0x"
                      + Long.toHexString(ident) + " to 0x"
                      + Long.toHexString(newIdent) + " while dispatching to "
                      + msg.target.getClass().getName() + " "
                      + msg.callback + " what=" + msg.what);
          }

          msg.recycleUnchecked();
      }
  }

代碼比較長(zhǎng),但是真的比較容易理解的,第一句執(zhí)行final Looper me = myLooper()獲取一個(gè)Looper對(duì)象,怎么獲取的呢?在myLooper中涉及到了ThreadLocal,對(duì)ThreadLocal不了解的,看我的第二篇博客。


  /**
     * Return the Looper object associated with the current thread.  Returns
     * null if the calling thread is not associated with a Looper.
     */
    public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }

如果sThreadLocal.get()返回了NULl,那么程序就會(huì) throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); ,尼瑪,如果主線(xiàn)程在這都拋了異常,那還玩毛線(xiàn),所以必然有sThreadLocal.set()?;氐絼偛?,在執(zhí)行消息循環(huán)Looper.loop之前,有一句關(guān)鍵的代碼, Looper.prepareMainLooper(),這句話(huà)可以創(chuàng)建UI線(xiàn)程所需要的Looper,跟蹤進(jìn)去。

 public static void prepareMainLooper() {
        //代碼在下面
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
          //從sThreadLocal中獲取Looper,系統(tǒng)默認(rèn)給我們創(chuàng)建了sMainLooper
            sMainLooper = myLooper();
        }
    }

  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));
    }

在sThreadLocal.get() 為NULL的情況下,直接以餓漢式的方式new了一個(gè)Looper, 調(diào)用sThreadLocal的set方法,這一步,通過(guò)sThreadLocal,其實(shí)是將Looper與當(dāng)前線(xiàn)程(UI線(xiàn)程)做了關(guān)聯(lián), 也就是說(shuō)上面創(chuàng)建的Looper對(duì)象me只能被主線(xiàn)程所訪(fǎng)問(wèn),其他線(xiàn)程訪(fǎng)問(wèn)不了?。?!,這就是ThreadLocal的厲害之處。Looper我們稱(chēng)之是消息循環(huán)器,就是不斷的把消息從消息隊(duì)列中取出來(lái),看一個(gè)創(chuàng)建Looper干了什么。

private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

主要是初始化了一個(gè)消息隊(duì)列,原來(lái)消息隊(duì)列是Looper里面的成員,記住了?。?!,還保留了當(dāng)前線(xiàn)程,有了mThread,我們就可以知道這個(gè)Looper是哪一個(gè)線(xiàn)程的Looper。Looper的成員非常少,就幾個(gè),看下面。

    // sThreadLocal.get() will return null unless you've called prepare().
     static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
   
     private static Looper sMainLooper;  // guarded by Looper.class

     final MessageQueue mQueue;
  
     final Thread mThread;

OK,在A(yíng)ctivityThread中的Looper.loop()這個(gè)死循環(huán)啟動(dòng)之前,需要執(zhí)行 Looper.prepareMainLooper(),這個(gè)方法執(zhí)行以后,我們知道發(fā)生了以下幾件事情。

  • 1、以餓漢式的方式創(chuàng)建了主線(xiàn)程的Looper對(duì)象
  • 2、用sThreadLocal將主線(xiàn)程與這個(gè)Looper對(duì)象關(guān)聯(lián)起來(lái)
  • 3、sThreadLocal.get一個(gè)Looper對(duì)象,賦值給sMainLooper。

繼續(xù)看Looper.loop()里面,第二句關(guān)鍵代碼是final MessageQueue queue = me.mQueue;即獲取Looper中的消息隊(duì)列,之后是一個(gè)死循環(huán),對(duì)消息隊(duì)列里面的消息進(jìn)行遍歷,在這里我們先留一個(gè)問(wèn)題 消息是怎么存到消息隊(duì)列里面去的?

 for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

            msg.target.dispatchMessage(msg);

            msg.recycleUnchecked();
        }

在這個(gè)死循環(huán)中遍歷,通過(guò)queue.next()取出消息。

  Message next() {
        
        for (;;) {
          
            //這句代碼水比較深,先跳過(guò)
            nativePollOnce(ptr, nextPollTimeoutMillis);

            synchronized (this) {
                // Try to retrieve the next message.  Return if found.
                final long now = SystemClock.uptimeMillis();
                Message prevMsg = null;
                Message msg = mMessages;
                if (msg != null && msg.target == null) {
                    // Stalled by a barrier.  Find the next asynchronous message in the queue.
                    do {
                        prevMsg = msg;
                        msg = msg.next;
                    } while (msg != null && !msg.isAsynchronous());
                }
                if (msg != null) {
                    if (now < msg.when) {
                        // Next message is not ready.  Set a timeout to wake up when it is ready.
                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                    } else {
                        // Got a message.
                        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 {
                    // No more messages.
                    nextPollTimeoutMillis = -1;
                }

            } 
        }
    }

在同步synchronized中,這一大段代碼也就是寫(xiě)消息何時(shí)出隊(duì)列的事情。

if (now < msg.when) {
         // Next message is not ready.  Set a timeout to wake up when it is ready.
            nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
        }

nextPollTimeoutMillis表示消息出隊(duì)列的時(shí)間,如果現(xiàn)在的時(shí)間now比Message要執(zhí)行的時(shí)間msg.when要小,就減去現(xiàn)在的時(shí)間,計(jì)算一個(gè)新的時(shí)間給nextPollTimeoutMillis。如果消息的執(zhí)行時(shí)間已經(jīng)到了,那么就取出這個(gè)消息返回并調(diào)用msg.markInUse(),把消息的狀態(tài)賦值為使用之中。

OK,在上面那個(gè)for循環(huán)中,消息是取到之后,就要進(jìn)行消息的分發(fā)了,消息的分發(fā)也是有一套順序的。調(diào)用 msg.target.dispatchMessage(msg),進(jìn)行消息的分發(fā),不知道target是什么的(是Handler對(duì)象,標(biāo)識(shí)這個(gè)消息被誰(shuí)處理),去看我的第一篇博客。

    /**
     * Handle system messages here.
     */
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

這里具體可以看我第一篇博客中****Message的處理順序****章節(jié),可以知道Message是怎么進(jìn)行分發(fā)的,從消息的分發(fā)可以看到,如果沒(méi)有Runnable的類(lèi)型的消息callback以及沒(méi)有Callback類(lèi)型的回調(diào)mCallback,那么就會(huì)回調(diào)Handler的handleMessge。

   private Handler  handler=new Handler(){
        @Override
        public void handleMessage(Message msg) {
           dosomething();
        }
    };

上面試我們常常寫(xiě)的代碼,走到這,相信你已經(jīng)知道我們常寫(xiě)的那個(gè)套路是怎么來(lái)的了。在Looper.looper中還有最后一句代碼 msg.recycleUnchecked();這個(gè)就不用講了,主要做消息的回收操作,這里消息會(huì)進(jìn)入消息的全局池中。

上面留下了一個(gè)問(wèn)題****消息是怎么存到消息隊(duì)列里面去的?****現(xiàn)在來(lái)分析分析,這個(gè)從我們發(fā)送消息(handler.sendMessage())來(lái)入手,經(jīng)過(guò)查看源碼,sendMessage中會(huì)掉一系列方法,最終走到enqueueMessage中。如下圖。


對(duì)于enqueueMessage中代碼就不分析了,現(xiàn)在我們知道消息是怎么進(jìn)入消息隊(duì)列的,又是怎么被Looper給取走,交給Handler去處理的了,整個(gè)消息機(jī)制基本就弄清楚了。其實(shí),嚴(yán)格來(lái)說(shuō),消息可以分為系統(tǒng)消息和我們自定義的消息,自定義的消息就是發(fā)送一個(gè)Message,然后在handlerMessage中進(jìn)行處理,那么系統(tǒng)的消息呢,比如四大組件的生命周期回掉是系統(tǒng)消息,跨進(jìn)程通信也是系統(tǒng)消息,應(yīng)用程序退出還是一個(gè)系統(tǒng)消息。這些消息在哪里?誰(shuí)來(lái)處理呢?在A(yíng)ctivityThread中有一個(gè)成員final H mH = new H();這個(gè)mH就是來(lái)處理系統(tǒng)消息的。

 private class H extends Handler {
        public static final int LAUNCH_ACTIVITY         = 100;
        //...
        public static final int ENTER_ANIMATION_COMPLETE = 149;

        String codeToString(int code) {
            if (DEBUG_MESSAGES) {
                switch (code) {
                    case LAUNCH_ACTIVITY: return "LAUNCH_ACTIVITY";
                      //...
                    case ENTER_ANIMATION_COMPLETE: return "ENTER_ANIMATION_COMPLETE";
                }
            }
            return Integer.toString(code);
        }
        public void handleMessage(Message msg) {
            if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
            switch (msg.what) {
                  //...
                case LAUNCH_ACTIVITY: {
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
                    final ActivityClientRecord r = (ActivityClientRecord) msg.obj;

                    r.packageInfo = getPackageInfoNoCheck(
                            r.activityInfo.applicationInfo, r.compatInfo);
                    handleLaunchActivity(r, null);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                } break;
            
                case PAUSE_ACTIVITY:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
                    handlePauseActivity((IBinder)msg.obj, false, (msg.arg1&1) != 0, msg.arg2,
                            (msg.arg1&2) != 0);
                    maybeSnapshot();
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                case PAUSE_ACTIVITY_FINISHING:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
                    handlePauseActivity((IBinder)msg.obj, true, (msg.arg1&1) != 0, msg.arg2,
                            (msg.arg1&1) != 0);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
             
                case HIDE_WINDOW:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityHideWindow");
                    handleWindowVisibility((IBinder)msg.obj, false);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                case RESUME_ACTIVITY:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityResume");
                    handleResumeActivity((IBinder) msg.obj, true, msg.arg1 != 0, true);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
              
                case DESTROY_ACTIVITY:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityDestroy");
                    handleDestroyActivity((IBinder)msg.obj, msg.arg1 != 0,
                            msg.arg2, false);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                case CREATE_SERVICE:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceCreate");
                    handleCreateService((CreateServiceData)msg.obj);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                case BIND_SERVICE:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceBind");
                    handleBindService((BindServiceData)msg.obj);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                case UNBIND_SERVICE:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceUnbind");
                    handleUnbindService((BindServiceData)msg.obj);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                case SERVICE_ARGS:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceStart");
                    handleServiceArgs((ServiceArgsData)msg.obj);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                case STOP_SERVICE:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceStop");
                    handleStopService((IBinder)msg.obj);
                    maybeSnapshot();
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
             
                case SUICIDE:
                    Process.killProcess(Process.myPid());
                    break;
              //...
            }
            if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + codeToString(msg.what));
        }
    }

看到了吧,如果要退出應(yīng)用程序,需要發(fā)送一個(gè)SUICIDE消息,綁定服務(wù)需要發(fā)送一個(gè)BIND_SERVICE消息等等。

最后總結(jié)一個(gè)Android消息機(jī)制涉及到的類(lèi)以及類(lèi)的重要方法,在整個(gè)機(jī)制中它們扮演著不同的角色也承擔(dān)著各自的不同責(zé)任。

  • Thread
    負(fù)責(zé)業(yè)務(wù)邏輯的實(shí)施。
    線(xiàn)程中的操作是由各自的業(yè)務(wù)邏輯所決定的,視具體情況進(jìn)行。

  • Handler
    負(fù)責(zé)發(fā)送消息和處理消息。
    通常的做法是在主線(xiàn)程中建立Handler并利用它在子線(xiàn)程中向主線(xiàn)程發(fā)送消息,在主線(xiàn)程接收到消息后會(huì)對(duì)其進(jìn)行處理

  • MessageQueue
    負(fù)責(zé)保存消息。
    Handler發(fā)出的消息均會(huì)被保存到消息隊(duì)列MessageQueue中,系統(tǒng)會(huì)根據(jù)Message距離觸發(fā)時(shí)間的長(zhǎng)短決定該消息在隊(duì)列中位置。在隊(duì)列中的消息會(huì)依次出隊(duì)得到相應(yīng)的處理。

  • Looper
    負(fù)責(zé)輪詢(xún)消息隊(duì)列。
    Looper使用其loop()方法一直輪詢(xún)消息隊(duì)列,并在消息出隊(duì)時(shí)將其派發(fā)至對(duì)應(yīng)的Handler.

  • ThreadLocal
    將線(xiàn)程和Looper相關(guān)聯(lián)

Please accept mybest wishes for your happiness and success

參考資料:http://blog.csdn.net/lfdfhl/article/details/53332936

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容