Android Handler消息傳遞機制

1. Handler消息傳遞機制初步認識:什麼是Handler? 
handler通俗一點講就是用來在各個線程之間發送數據的處理對象。在任何線程中,只要得到了另外一個線程的handler,則能夠經過handler.sendMessage(message)方法向那個線程發送數據。基於這個機制,咱們在處理多線程的時候能夠新建一個thread,這個thread擁有UI線程中的一個handler。當thread處理完一些耗時的操做後經過傳遞過來的handler向UI線程發送數據,由UI線程去更新界面。 
主線程:運行全部UI組件,它經過一個消息隊列來完成此任務。設備會將用戶 的每項操做轉換爲消息,並將它們放入正在運行的消息隊列中。主線程位於一個循環中,並處理每條消息。若是任何一個消息用時超過5秒,Android將拋出 ANR。因此一個任務用時超過5秒,應該在一個獨立線程中完成它,或者延遲處理它,當主線程空閒下來再返回來處理它。android

2.經常使用類:(Handler、Looper、Message、MessageQueue) 
Message:消息,其中包含了消息ID,消息處理對象以及處理的數據等,由MessageQueue統一列隊,終由Handler處理。 
Handler:處理者,負責Message的發送及處理。使用Handler時,須要實現 handleMessage(Message msg)方法來對特定的Message進行處理,例如更新UI等。Handler類的主要做用:(有兩個主要做用)1)、在工做線程中發送消息;2)、在 主線程中獲w/取、並處理消息。 
MessageQueue:消息隊列,用來存放Handler發送過來的消息,並按照FIFO規則執行。固然,存放Message並不是實際意義的保存,而是將Message串聯起來的,等待Looper的抽取。 
Looper:消息泵,不斷地從MessageQueue中抽取Message執行。所以,一個MessageQueue須要一個Looper。數組

3.Handler、Looper、Message、MessageQueue之間的關係:網絡

  • Looper和MessageQueue一一對應,建立一個Looper的同時,會建立一個MessageQueue;
  • 而Handler與它們的關係,只是簡單的彙集關係,即Handler裏會引用當前線程裏的特定Looper和MessageQueue;
  • 在一個線程中,只能有一個Looper和MessageQueue,可是能夠有多個Handler,並且這些Handler能夠共享一個Looper和MessageQueue;
  • Message被存放在 MessageQueue中,一個 MessageQueue中能夠包含多個Message對象

【備註:】 
Looper對象用來爲一個線程開啓一個消息循環,從而操做MessageQueue; 
默認狀況下,Android建立的線程沒有開啓消息循環Looper,可是主線程例外。 
系統自動爲主線程建立Looper對象,開啓消息循環; 
因此主線程中使用new來建立Handler對象。而子線程中不能直接new來建立Handler對象就會異常。 
子線程中建立Handler對象,步驟以下: 
Looper.prepare(); 
Handler handler = new Handler() { 
//handlemessage(){} 

Looper.loop();多線程

4.Handler類中經常使用方法: 
(1) handleMessage() 用在主線程中,構造Handler對象時,重寫handleMessage()方法。該方法根據工做線程返回的消息標識,來分別執行不一樣的操做。 
(2) sendEmptyMessage() 用在工做線程中,發送空消息。 
(3) sendMessage() 用在工做線程中,當即發送消息。ide

5.Message消息類中經常使用屬性: 
(1) arg1 用來存放整型數據 
(2) arg2 用來存放整型數據 
(3) obj 用來存放Object數據 
(4) what 用於指定用戶自定義的消息代碼,這樣便於主線程接收後,根據消息代碼不一樣而執行不一樣的相應操做。oop

上一下Demo的示例代碼:this

複製代碼
private Handler handler = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        text_main_info = (TextView) findViewById(R.id.text_main_info);
        pDialog = new ProgressDialog(MainActivity.this);
        pDialog.setMessage("Loading...");
        image_main = (ImageView) findViewById(R.id.image_main);

        // 主線程中的handler對象會處理工做線程中發送的Message。根據Message的不一樣編號進行相應的操做。
        handler = new Handler() {
                public void handleMessage(android.os.Message msg) {
                        // 工做線程中要發送的信息全都被放到了Message對象中,也就是上面的參數msg中。要進行操做就要先取出msg中傳遞的數據。
                        switch (msg.what) {
                        case 0:
                                // 工做線程發送what爲0的信息表明線程開啓了。主線程中相應的顯示一個進度對話框
                                pDialog.show();
                                break;
                        case 1:
                                // 工做線程發送what爲1的信息表明要線程已經將須要的數據加載完畢。本案例中就須要將該數據獲取到,顯示到指定ImageView控件中便可。
                                image_main.setImageBitmap((Bitmap) msg.obj);
                                break;
                        case 2:
                                // 工做線程發送what爲2的信息表明工做線程結束。本案例中,主線程只須要將進度對話框取消便可。
                                pDialog.dismiss();
                                break;
                        }
                }
        };

        new Thread(new Runnable() {
                @Override
                public void run() {
                        // 當工做線程剛開始啓動時,但願顯示進度對話框,此時讓handler發送一個空信息便可。
                        // 當發送這個信息後,主線程會回調handler對象中的handleMessage()方法。handleMessage()方法中
                        // 會根據message的what種類來執行不一樣的操做。
                        handler.sendEmptyMessage(0);

                        // 工做線程執行訪問網絡,加載網絡圖片的任務。
                        byte[] data = HttpClientHelper.loadByteFromURL(urlString);
                        // 工做線程將網絡訪問獲取的字節數組生成Bitmap位圖。
                        Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0,
                                        data.length);
                        // 工做線程將要發送給主線程的信息都放到一個Message信息對象中。
                        // 而Message對象的構建建議使用obtain()方法生成,而不建議用new來生成。
                        Message msgMessage = Message.obtain();
                        // 將須要傳遞到主線程的數據放到Message對象的obj屬性中,以便於傳遞到主線程。
                        msgMessage.obj = bitmap;
                        // Message對象的what屬性是爲了區別信息種類,而方便主線程中根據這些類別作相應的操做。
                        msgMessage.what = 1;
                        // handler對象攜帶着Message中的數據返回到主線程
                        handler.sendMessage(msgMessage);

                        // handler再發出一個空信息,目的是告訴主線程工做線程的任務執行完畢。通常主線程會接收到這個消息後,
                        // 將進度對話框關閉
                        handler.sendEmptyMessage(2);
                }
        }).start();
}
複製代碼
相關文章
相關標籤/搜索