深入理解Android消息處理系統——Looper、Handler、Thread

轉自:http://blog.sina.com.cn/s/blog_5da93c8f0100y4ul.html


Android Looper和Handler

Message消息,其中包含了消息ID,消息處理對象以及處理的數據等,由MessageQueue統一列隊,終由Handler處理。

Handler:處理者,負責Message的發送及處理。使用Handler時,需要實現handleMessage(Message msg)方法來對特定的Message進行處理,例如更新UI等。

MessageQueue消息隊列,用來存放Handler發送過來的消息,並按照FIFO規則執行。當然,存放Message並非實際意義的保存,而是將Message以鏈表的方式串聯起來的,等待Looper的抽取。

Looper消息泵,不斷地從MessageQueue中抽取Message執行。因此,一個MessageQueue需要一個Looper

Thread線程,負責調度整個消息循環,即消息循環的執行場所。

    Android 系統的消息隊列和消息循環都是針對具體線程的,一個線程可以存在(當然也可以不存在)一個消息隊列和一個消息循環(Looper),特定線程的消息只能分發給本線程,不能進行跨線程,跨進程通訊。但是創建的工作線程默認是沒有消息循環和消息隊列的,如果想讓該線程具有消息隊列和消息循環,需要在線程中首先調用Looper.prepare()來創建消息隊列,然後調用Looper.loop()進入消息循環。 如下例所示:

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.loop()之後的代碼不會被立即執行,當調用後 mHandler.getLooper().quit()後,loop纔會中止,其後的代碼才能得以運行。Looper對象通過MessageQueue 來存放消息和事件。一個線程只能有一個Looper,對應一個MessageQueue。

這樣你的線程就具有了消息處理機制了,在Handler中進行消息處理。

        
Activity是一個UI線程,運行於主線程中,Android系統在啓動的時候會爲Activity創建一個消息隊列和消息循環(Looper)。詳細實現請參考ActivityThread.java文件。

Android應用程序進程在啓動的時候,會在進程中加載ActivityThread類,並且執行這個類的main函數,應用程序的消息循環過程就是在這個main函數裏面實現的

public final class ActivityThread {
......

public static final void main(String[] args) {
......

Looper.prepareMainLooper();

......

ActivityThread thread = new ActivityThread();
thread.attach(false);

......

Looper.loop();

......

thread.detach();

......
}
}

這個函數做了兩件事情,一是在主線程中創建了一個ActivityThread實例,二是通過Looper類使主線程進入消息循環中,這裏我們只關注後者。

    首先看Looper.prepareMainLooper函數的實現,這是一個靜態成員函數,定義在frameworks/base/core/java/android/os/Looper.java文件中:


  1 //Looper類分析
  2 //沒找到合適的分析代碼的辦法,只能這麼來了。每個重要行的上面都會加上註釋
  3 //功能方面的代碼會在代碼前加上一段分析
  4 public class Looper {
  5    //static變量,判斷是否打印調試信息。
  6     private static final boolean DEBUG = false;
  7     private static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
  8 
  9 // sThreadLocal.get() will return null unless you've called prepare().
 10 //線程本地存儲功能的封裝,TLS,thread local storage,什麼意思呢?因爲存儲要麼在棧上,例如函數內定義的內部變量。要麼在堆上,例如new或者malloc出來的東西。
 11 //但是現在的系統比如Linux和windows都提供了線程本地存儲空間,也就是這個存儲空間是和線程相關的,一個線程內有一個內部存儲空間,這樣的話我把線程相關的東西就存儲到
 12 //這個線程的TLS中,就不用放在堆上而進行同步操作了。
    //
ThreadLocal並不是一個Thread,而是Thread的局部變量。
 13     private static final ThreadLocal sThreadLocal = new ThreadLocal();
 14 //消息隊列,MessageQueue,看名字就知道是個queue..
 15     final MessageQueue mQueue;
 16     volatile boolean mRun;
 17 //和本looper相關的那個線程,初始化爲null
 18     Thread mThread;
 19     private Printer mLogging = null;
 20 //static變量,代表一個UI Process(也可能是service吧,這裏默認就是UI)的主線程
 21     private static Looper mMainLooper = null;
 22     
 23      
 29 //往TLS中設上這個Looper對象的,如果這個線程已經設過了Looper的話就會報錯,這說明,一個線程只能設一個looper
    //
 31     public static final void prepare() {
 32         if (sThreadLocal.get() != null) {
 33             throw new RuntimeException("Only one Looper may be created per thread");
 34         }
 35         sThreadLocal.set(new Looper());
 36     }
 37     
 38     
 43  //由framework設置的UI程序的主消息循環,注意,這個主消息循環是不會主動退出的
 44 //    
 45     public static final void prepareMainLooper() {
 46         prepare();
 47         setMainLooper(myLooper());
 48 //判斷主消息循環是否能退出....
 49 //通過quit函數向looper發出退出申請
 50         if (Process.supportsProcesses()) {
 51             myLooper().mQueue.mQuitAllowed = false;
 52         }
 53     }
 54 
 55     private synchronized static void setMainLooper(Looper looper) {
 56         mMainLooper = looper;
 57     }
 58     
 59     
 61     public synchronized static final Looper getMainLooper() {
 62         return mMainLooper;
 63    
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章