handler_looper機制,相互的關係和相互的信息傳遞過程詳解

關於handler_loop機制:
1,什麼是handlerloop機制:
handler_loop機制,準確的說是handler,message,messageQueuen,loop機制,因爲他們當中,有兩個是底層中的,所以,我們所操作的只有handler,和message這兩個,爲了實現子線程中操作UI界面,Android中引入了Handler消息傳遞機制,目的是打破對主線程的依賴性。
2,handler_loop機制的作用
因爲大家都知道在子線程中無法對ui控件進行操作,會出現CalledFromWrongThreadException異常,
如果大量的數據操作在主線程中操作的話會因爲長時間的等待排序,超過5秒,導致anr的出現會報錯,所以,如何將子線程中的數據傳遞給主線程呢?在此,就可以通過handler機制進行操作。
3既然瞭解了這個機制,那麼什麼是handler呢?
handler,其實就是一個消息處理對象,他的作用就是將消息從一個線程,轉移到另一個線程,(這裏以主線程和子線程爲例);
只要你在子線程中,得到了主線程中的handler對象就可以通過handler.sendMessage的方法將數據轉移到主線程,然後就可以進行操作了。
4,什麼是Message.:
消息,被傳遞和處理的數據。其中包含了消息ID,消息處理對象以及處理的數據等,由MessageQueue統一列隊,終由Handler處理。通俗的講,就是handler要攜帶的數據。
5,什麼是MessageQueue:


MessageQueue:消息隊列,本質是一個數據結構,用來存放Handler發送過來的消息,並按照FIFO規則執行。當然,存放Message並非實際意義的保存,而是將Message串聯起來,等待Looper的抽取。其實就是讓傳遞過來的Messsage排隊等待的地方。
6,什麼是looper:
消息泵或循環器,不斷從MessageQueue中抽取Message。因此,一個MessageQueue需要一個Looper。如果你把MessageQueue當做一個傳送帶的話,那麼looper就是傳送帶終端接收處理產品的一個勞動者。接收穫取。




注意一點:
【重點】:使用Message需要注意4點:
1、Message雖然也可以通過new來獲取,但是通常使用Message.obtain()或Handler.obtainMessage()方法來從消息池中獲得空消息對象,以節省資源;
2、如果一個Message只需要攜帶簡單的int型數據,應優先使用arg1和arg2屬性來傳遞數據,這樣比其他方式節省內存;
3、儘可能使用Message.what來標識信息,以便用不同的方式處理Message;
4、如果需要從工作線程返回很多數據信息,可以藉助Bundle對象將這些數據集中到一起,然後存放到obj屬性中,再返回到主線程。


【備註:】
Looper對象用來爲一個線程開啓一個消息循環,從而操作MessageQueue;
默認情況下,Android創建的線程沒有開啓消息循環Looper,但是主線程例外。
系統自動爲主線程創建Looper對象,開啓消息循環;
所以主線程中使用new來創建Handler對象。而子線程中不能直接new來創建Handler對象就會異常。
子線程中創建Handler對象,步驟如下:

Looper.prepare();
Handler handler = new Handler() {
    //handlemessage(){}
}
Looper.loop();



說了這麼多現在再說一說消息傳遞的整個流程吧:(現附上一片代碼):


import android.app.Activity;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.PersistableBundle;

import com.yztc.mvpdemo.R;

/**
 * Created by Administrator on 2016/11/17.
 */
public class Activitys extends Activity {
//聲明並創建handelr對象,用於子線程發送消息,並且用於主線程中接收消息
    Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {//此處的參數就是接收到的消息對象
            super.handleMessage(msg);
//對消息對象進行判斷
            switch (msg.what) {
//如果標籤是0的話,就操作0,標籤的handler發送的數據,因爲一個可已有多個handelr,所以接受的是以標籤是識別的
                case 0:

                    //此處將傳遞來的數據進行操作,用於更新ui;

                    break;
            }


        }
    };

    @Override
    public void onCreate(Bundle savedInstanceState, PersistableBundle persistentState) {
        super.onCreate(savedInstanceState, persistentState);
        setContentView(R.layout.activity_main);
//創建子線程用於進行大量的耗時操作
        new Thread(new Runnable() {
            @Override
            public void run() {
//得到meddage對象,
                Message message = Message.obtain();
//打上標籤
                message.what = 0;
//將需要傳遞出去的數據傳遞出去,
                message.obj = "呵呵,這裏是子線程";
//發送消息
                handler.sendMessage(message);

            }
        }).start();

    }
}
整個流程就結束了,因爲很多東西是在底層操作的,如果你不想深入瞭解,那麼你看到這個地方就可以結束了

如果你想更加升入的瞭解一些底層的東西,可以繼續向下看:

首先我先將handelr,looper,message,messageQoueue中的一些方法展示出來:

Handler類中常用方法:
  1. handleMessage()    用在主線程中,構造Handler對象時,重寫handleMessage()方法。該方法根據工作線程返回的消息標識,來分別執行不同的操作。
  2. sendEmptyMessage()     用在工作線程中,發送空消息。
  3. sendMessage()      用在工作線程中,立即發送消息。
Message消息類中常用屬性
  1. arg1     用來存放整型數據
  2. arg2      用來存放整型數據
  3. obj        用來存放Object數據
  4. what     用於指定用戶自定義的消息代碼,這樣便於主線程接收後,根據消息代碼不同而執行不同的相應操作。

A、Handler.java:(3個屬性,10個方法)
3個屬性:
  • final MessageQueue mQueue;    封裝好的Message被handler發送出去,其實就是放到了MessageQueue消息隊列中。
  • final Looper mLooper;  每個handler都有一個looper爲其不斷接收消息隊列中的消息,並返回給handler。
  • final Callback mCallback;    被handler接收到的消息要通過Callback接口中的handleMessage()方法來進行處理。

10個方法:
  • public boolean handleMessage(Message msg);    Callback接口中的handleMessage()方法,用來處理返回給handler的消息的。
  • public final Message obtainMessage()     獲取Message對象,其本質還是調用Message類的obtain()方法來獲取消息對象。
  • public final boolean sendMessage(Message msg)      發送消息
  • public final boolean sendEmptyMessage(int what)      發送只有what屬性的消息
  • public final boolean post(Runnable r)                          發送消息
  • public final boolean postAtTime(Runnable r, long uptimeMillis)         定時發送消息
  • public final boolean postDelayed(Runnable r, long delayMillis)         延遲發送消息
  • public void dispatchMessage(Message msg)                分發消息。當Looper循環接收消息隊列中的消息時,就在不斷調用handler的分發消息方法,從而觸發Callback接口中的消息處理方法handleMessage()來對消息進行處理。
  • public final boolean sendMessageDelayed(Message msg, long delayMillis)     sendMessage()就是在調用延時發送消息的方法。
  • public boolean sendMessageAtTime(Message msg, long uptimeMillis)     延時發送消息的方法就是在調用定時發送消息的方法。
  • private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis)     將消息壓入消息隊列中

B、MessageQueue.JAVA:(1個方法)
  •    final boolean enqueueMessage(Message msg, long when)    handler發送的消息正是通過該方法被加進了消息隊列中。因爲消息隊列中有消息,從而觸發了Looper通過loop()方法循環接收所有的消息。

C、Looper.JAVA:(3個屬性,5個方法)
3個屬性:
  •     static final ThreadLocal<LoopersThreadLocal = new ThreadLocal<Looper>(); 正是由於該線程本地變量,保證了一個線程中只能保存一個Looper對象,也就是說一個Thread中只能有一個Looper對象
  •     final MessageQueue  mQueue; 正是由於MessagQueue中的消息,才觸發了Looper的loop()方法。
  •     private static Looper mMainLooper = null; 該屬性是主線程中自動創建的Looper對象。

5個方法:
  • public static void prepare() 每個handler所在的線程都必須有一個Looper提前準備好。
  • public static void prepareMainLooper() 主線程中的的Looper已經被自動準備好。而該方法不需要手工調用。
  • public static Looper getMainLooper() 獲取主線程中的Looper對象
  • public static void loop() Looper的作用就是循環接收消息隊列中的消息。該方法中執行了一個無限循環。
  • public static Looper myLooper() 該方法的作用是從線程本地變量中獲取到當前線程的Looper對象。

D、Message.java:(10個屬性,7個方法)
10個屬性:
  • public int what;     該屬性一般用來標識消息執行的狀態。
  • public int arg1;     用來存放整型數據的屬性。
  • public int arg2;     用來存放整型數據的屬性。
  • public Object obj;    用來存放複雜消息數據的屬性。
  • Bundle  data;          用來存放複雜消息數據的屬性。
  • Handler target;       標識該消息要被髮送給哪個Handler對象。
  • Message sPool;     消息池對象。
  • int sPoolSize;         記錄消息池中剩餘消息的數量。
  • int MAX_POOL_SIZE=50;     消息池中最大消息數量。
  • Messenger replyTo;        定義消息的信使對象,將來可以用於跨APP的消息傳遞。

7個方法:
  • public static Message obtain()       從消息池中獲取消息對象。
  • public void recycle()                      往消息池中歸還消息對象。
  • public void setTarget(Handler target)           給消息handler對設置接收該消息的目標象。
  • public Handler getTarget()              獲取消息的接收handler對象。
  • public void sendToTarget()             將消息發送到目標handler對象。其本質是調用handler對象的sendMessage()方法來發送當前消息對象。
  • public void setData(Bundle data)     將Bundle對象設置到message對象中Bundle屬性中。
  • public Bundle getData()                   從消息對象中獲取Bundle屬性的數據。

先說一下信息傳遞的過程:(消息傳遞的執行順序)

消息是如何從子線程中傳遞到主線程中的,中間發生了什麼?

開始傳遞handler.sendmeddage()---》調用的是底層的handler.sendMessageDelayed()方法---》繼續往底層深入handler.sendmessageAtTime()----->接着將消息傳遞給隊列讓隊列進行管理handler.enquouoMessage()-------->消息隊列接收到過來的消息messageQueue.enqueueMessage()--------->looper開始操作消息looper.loop()----->得到消息msg=messageQueue.next()------->分發消息msg.target.dispatchmessage(mdg)--------->msg的使命結束,開始進入回收被回收到了消息池中以供下次使用msg.recycle()----回收的同時----handlerMessage消息被傳入到主線程,兩者是幾乎同時進行的這樣整個消息傳遞結束,






發佈了39 篇原創文章 · 獲贊 14 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章