1. 程式人生 > >Android單執行緒模型中Message、Handler、Message Queue、Looper之間的關係

Android單執行緒模型中Message、Handler、Message Queue、Looper之間的關係

四者之間的關係:

Handler獲取當前執行緒中的looper物件,looper用來從存放Message的MessageQueue中取出Message,再有Handler進行Message的分發和處理.

簡單定義:

1、Message Queue(訊息佇列): 用來存放通過Handler釋出的訊息,通常附屬於某一個建立它的執行緒,可以通過Looper.myQueue()得到當前執行緒的訊息佇列. 
2、Handler: 可以釋出或者處理一個訊息或者操作一個Runnable,通過Handler釋出訊息,訊息將只會傳送到與它關聯的訊息佇列,然也只能處理該訊息佇列中的訊息. 3、Looper: 是Handler和訊息佇列之間通訊橋樑,程式元件首先通過Handler把訊息傳遞給Looper,Looper把訊息放入佇列。Looper也把訊息佇列裡的訊息廣播給所有的Handler:Handler接受到訊息後呼叫handleMessage進行處理.
4、Message: 訊息的型別,在Handler類中的handleMessage方法中得到單個的訊息進行處理,在單執行緒模型下,為了執行緒通訊問題,Android設計了一個Message Queue(訊息佇列), 執行緒間可以通過該Message Queue並結合Handler和Looper元件進行資訊交換。

詳細介紹:

1. Message Message訊息,理解為執行緒間交流的資訊,處理資料後臺執行緒需要更新UI,則傳送Message內含一些資料給UI執行緒。 2. Handler Handler處理者,是Message的主要處理者,負責Message的傳送,Message內容的執行處理。後臺執行緒就是通過傳進來的 Handler物件引用來sendMessage(Message)。而使用Handler,需要implement 該類的 handleMessage(Message)方法,它是處理這些Message的操作內容,例如Update UI。通常需要子類化Handler來實現handleMessage方法。 3. Message Queue Message Queue訊息佇列,用來存放通過Handler釋出的訊息,按照先進先出執行。 每個message queue都會有一個對應的Handler。Handler會向message queue通過兩種方法傳送訊息:sendMessage或post。這兩種訊息都會插在message queue隊尾並按先進先出執行。但通過這兩種方法傳送的訊息執行的方式略有不同:通過sendMessage傳送的是一個message物件,會被 Handler的handleMessage()函式處理;而通過post方法傳送的是一個runnable物件,則會自己執行。 4. Looper Looper是每條執行緒裡的Message Queue的管家。Android沒有Global的Message Queue,而Android會自動替主執行緒(UI執行緒)建立Message Queue,但在子執行緒裡並沒有建立Message Queue。所以呼叫Looper.getMainLooper()得到的主執行緒的Looper不為NULL,但呼叫Looper.myLooper() 得到當前執行緒的Looper就有可能為NULL。 判斷Handler物件裡面的Looper物件是屬於哪條執行緒的,則由該執行緒來執行! 1. 當Handler物件的建構函式的引數為空,則為當前所線上程的Looper; 2. Looper.getMainLooper()得到的是主執行緒的Looper物件,Looper.myLooper()得到的是當前執行緒的Looper物件。

原始碼:

  1. publicclass MainActivity extends Activity implements OnClickListener {  
  2.     private Button startbutton = null;  
  3.     private TextView text = null;  
  4.     private MyHandler mHandler = null;  
  5.     private Thread thread;  
  6.     @Override
  7.     protectedvoid onCreate(Bundle savedInstanceState) {  
  8.         super
    .onCreate(savedInstanceState);  
  9.         setContentView(R.layout.main);  
  10.         startbutton = (Button) findViewById(R.id.StartButton);  
  11.         startbutton.setOnClickListener(this);  
  12.         text = (TextView) findViewById(R.id.content);  
  13.     }  
  14.     @Override
  15.     publicvoid onClick(View v) {  
  16.         switch (v.getId()) {  
  17.         case R.id.StartButton:  
  18.             // 每次單擊都會建立一個新的執行緒,這肯定是不合適的
  19.             thread = new MyThread();  
  20.             thread.start();// 開啟一個子執行緒
  21.             break;  
  22.         }  
  23.     }  
  24.     privateclass MyHandler extends Handler {  
  25.         public MyHandler(Looper looper) {  
  26.             super(looper);  
  27.         }  
  28.         @Override
  29.         publicvoid handleMessage(Message msg) { // 處理訊息
  30.             System.out  
  31.                     .println("handle--id-->" + Thread.currentThread().getId());// 1
  32.             System.out.println("handle--name-->"
  33.                     + Thread.currentThread().getName());// main
  34.             text.setText(msg.obj.toString());// 此時handle在主執行緒當中,可以處理介面更新
  35.         }  
  36.     }  
  37.     /** 
  38.      * Android 會自動替主執行緒建立Message Queue ,在這個子執行緒裡並沒有建立Message Queue 。 所以,myLooper 
  39.      * 值為null ,而mainLooper 則指向主執行緒裡的Looper 。於是,執行到: mHandler = new MyHandler 
  40.      * (mainLooper); 此mHandler屬於主執行緒。 mHandler.sendMessage(m); 
  41.      * @author andieguo 
  42.      */
  43.     privateclass MyThread extends Thread {  
  44.         /** 
  45.          * Looper.myLooper();獲得當前的Looper Looper.getMainLooper ();獲得UI執行緒的Lopper 
  46.          */
  47.         @Override
  48.         publicvoid run() {  
  49.             System.out.println("MyThread------id------>"
  50.                     + Thread.currentThread().getId());  
  51.             System.out.println("MyThread------name------>"
  52.                     + Thread.currentThread().getName());  
  53.             Looper curLooper = Looper.myLooper();// MyThread執行緒
  54.             Looper mainLooper = Looper.getMainLooper();  
  55.             String msg;  
  56.             if (curLooper == null) {  
  57.                 // 把當前handler繫結在mainLooper執行緒上;此時mainLooper執行緒當中
  58.                 mHandler = new MyHandler(mainLooper);  
  59.                 msg = "curLooper is null";  
  60.             } else {  
  61.                 mHandler = new MyHandler(curLooper);// 將mHandler與curLooper繫結
  62.                 msg = "This is curLooper";  
  63.             }  
  64.             mHandler.removeMessages(0);  
  65.             Message m = mHandler.obtainMessage(111, msg);  
  66.             // mHandler物件而將訊息m傳給curLooper,然後放入MessageQueue裡。
  67.             // Looper物件看到MessageQueue裡有訊息m,就將它廣播出去,mHandler物件接到此訊息時,會呼叫其handleMessage()函式來處理
  68.             mHandler.sendMessage(m);// 將訊息新增到了curLooper相關聯的訊息佇列中;
  69.         }  
  70.     }  
  71. }  

結果驗證: