Android中非同步訊息處理機制

來源:互聯網
上載者:User

標籤:looper   messagequeue   handler   android訊息處理機制   



1. Thread Local Storage (線程局部儲存)     我們通過位於android.os包下的Looper.class源碼可以看到成員變數區有一個線程局部變數 sThreadLocal,該類的作用是線程局部儲存?那麼是線程局部儲存TLS?這個問題可以從變數範圍的角度來理解。          變數的常見範圍一般包括以下幾種。
  • 函數內部變數。其作用地區是該函數,即每次調用該函數,該變數都會重新回到初始值。
  • 類內部的變數。其作用就是該類所產生的對象,即只要該對象沒有被銷毀,則對象內部的變數則一直保持。
  • 類內部的靜態變數。其作用是整個進程,即只要在該進程中,該變數的值就會一直保持,無論使用多少類來構造這個對象,該變數只有一個賦值,且一直保持。
對於類內部的靜態變數而言,無論是從進程中那個線程引用該變數,其值總是相同的,因為編譯器內部為靜態變數分配了單獨的記憶體空間。但有時我們卻希望,當從同一個線程中引用該變數時,其值總是相同的, 而從不同的線程引用該變數,其值應該不同,即我們需要一種範圍為線程的變數定義,這就是線程局部儲存。
ThreadLocal內部其實是使用弱引用WeakReference來儲存當前線程對象,但是不同的線程有不同的ThreadLocal對象,因此會有一個用於區別的id,由此內部封裝了一個靜態內部類Values,這個類就相當於一個map,儲存了每一個線程的執行個體的值。
sThreadLocal在prepare()函數被調用的時候就進行了一次賦值,即構造一個新的LooperObject Storage Service到本地線程局部變數中,當然一個線程只能有一個Looper對象,否則會拋出如所示的異常。
          
Looper中有2個用於構造Looper對象的方法。一個是prepare(),另一個是prepareMainLooper()。prepare()我們已經說過了,下面說下prepareMainLooper()。prepareMainLooper(),由方法注釋我們可以知道,這個應用程式的mainlooper對象是由android環境建立的,所以你自己永遠沒必要調用這個函數。               
2. Looper我們可以從類注釋來瞭解Looper類的作用到底是幹什麼的。

Class used to run a message loop for a thread. Threads by default do not have a message loop associated with them; to create one, call prepare in the thread that is to run the loop, and then loop to have it process messages until the loop is stopped.

Most interaction with a message loop is through the Handler class.

This is a typical example of the implementation of a Looper thread, using the separation of prepare and loop to create an initial Handler to communicate with the Looper.

  class LooperThread extends Thread {      public Handler mHandler;      public void run() {          Looper.prepare();          mHandler = new Handler() {              public void handleMessage(Message msg) {                  // process incoming messages here              }          };          Looper.loop();      }  }
Looper類的作用就是給線上程內部建立一個訊息迴圈,當然線程自身內部是沒有一個訊息迴圈機制;在run()函數首行調用Looper.prepare(),即使建立了一個訊息迴圈隊列,然後在run函數尾行調用Looper.loop()則開始處理訊息直到訊息迴圈停止。大多數訊息迴圈的互動是通過Handler類進行的。

3. Handler這裡我們只從訊息迴圈機制角度來分析這個Handler。首先看Handler的建構函式
/**
     * Default constructor associates this handler with the queue for the
     * current thread.
     *
     * If there isn‘t one, this handler won‘t be able to receive messages.
     */
    public Handler() {
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                    klass.getCanonicalName());
            }
        }
         //從TLS(局部線程儲存)中取出已經存放好的Looper對象
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can‘t create handler inside thread that has not called Looper.prepare()");
        }
        //將Looper對象中的MessageQueue賦值給Handler中的對象
        mQueue = mLooper.mQueue;
        mCallback = null;
    }

然後我們在從使用的角度分析,這裡我只從非同步處理UI介面分析。我們(程式員)通過 Handler調用sendMessage()函數線上程內部向UI主線程發送一個Message對象,該Message對象會依次通過Handler中的函數
sendMessage(...) -> sendMessageDelayed(...) -> sendMessageAtTime(...) 
最終會通過sendMessageAtTime發送訊息對象。
public boolean sendMessageAtTime(Message msg, long uptimeMillis)
    {
        boolean sent = false;
        MessageQueue queue = mQueue;
        if (queue != null) {
            msg.target = this;
       
            //將訊息對象加入到訊息佇列
            sent = queue.enqueueMessage(msg, uptimeMillis);
        }
        else {
            RuntimeException e = new RuntimeException(
                this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
        }
        return sent;
    }

然後我們在來看看enqueueMessage進行了什麼操作。

    final  boolean enqueueMessage(Message msg, long when) {
                      ...
        if (needWake) {
            nativeWake(mPtr);
        }

                      ...
   }
nativeWake是一個java本地方法,這裡涉及了訊息機制中的Sleep-Wakeup機制,關於如何喚醒Looper線程的動作,這裡不做贅述,其最終就是調用了 native層的Looper的wake函數,喚醒了這個函數之後,就開始進行訊息迴圈
 

Android中非同步訊息處理機制

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.