【筆記】Android handler 消息處理機制

1.Looper類

looper是線程的消息循環處理器,每個線程只能有一個Looper對象,其內部有一個MessageQueue,所有消息都存放在這個隊列中。

新創建一個線程時,系統不會爲這個線程創建Looper,需要自己創建。Android在啓動時,爲主線程(UI 線程)創建一個looper 對象。

1.1 HandlerThread

public class HandlerThread extends Thread {
    int mPriority;
    int mTid = -1;
    Looper mLooper;
 
    public HandlerThread(String name) {
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }
    
    public HandlerThread(String name, int priority) {
        super(name);
        mPriority = priority;
    }
    
    protected void onLooperPrepared() {
    }
 
    @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();//Looper類的實例必須通過prepare函數創建
        synchronized (this) {
            mLooper = Looper.myLooper();//通過myLooper方法獲取Looper對象
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();//loop函數主要分發消息隊列中的消息。
        mTid = -1;
    }
    
    public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }
        
        // If the thread has been started, wait until the looper has been created.
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }
 
    public boolean quit() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quit();
            return true;
        }
        return false;
    }
 
}

下面我們主要看下Looper類中的loop方法:

public static void loop() {
        final Looper me = myLooper();
... ...
        final MessageQueue queue = me.mQueue;//消息隊列
 
        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();
 
        for (;;) {//無線循環
            Message msg = queue.next(); // might block

... ...
            msg.target.dispatchMessage(msg);//分發消息
 
... ...
 
            msg.recycle();
        }
    }

looper.loop() 就是在一個死循環中持續讀取MessageQueue 中的消息並dispatch。

Handler類

    public Handler(Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
... ...

        mLooper = Looper.myLooper();
... ...
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

Handler主要負責消息的發送和處理。在一個線程中可以只用一個Hander對象處理所以消息,也可以使用多個。

1.構造一個Handler對象,需要兩個參數,線程的Looper對象和消息處理函數,如果不指定looper,會使用當前線程的looper對象。
2.handler 對象創建時,調用的是當前線程的Looper對象作爲mLooper,同時調用mQueue = mLooper.mQueue , 即當前線程的消息隊列作爲自己將要處理的消息隊列(Handler.mQueue)。

3.並不是每個線程都默認有looper 對象,所以在創建handler對象之前,會先調用Looper.prepare(),爲當前Thread 創建一個looper 對象

 

Handler.sendMessage ->Handler.sendEmptyMessage ->... ->Handler.enqueueMessage


    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;//注意msg.target都是handler,因此在消息線程的loop函數處理消息時,msg.target.dispatchMessage會回到handler。
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
}

所有的發送消息接口,最後都會調用MessageQueue類中enqueueMessage函數,參數除了消息外,就是一個時間。而MessageQueue類中enqueueMessage函數只是把消息插入到消息隊列中的合適位置。

 

 

總結一下:

0. 一個線程有且僅有一個looper對象,looper對象中有一個MessageQueue 作爲消息隊列;

1.消息機制需要一個線程環境,裏面需要一個Looper對象,並且在線程的run函數中調用Looper.loop()函數;

2.函數需要一個handler來發送和處理消息。Hander要有一個Looper對象,來指定其線程,還要實現handleMessage函數。

 


Looper線程首先是一個Thread,由Java 標準線程變化過來:

一般的:

class LooperThread extends Thread {    //繼承Thread 類
    public Handler mHandler;           //需要一個handler對象發送處理消息
    public vold run {                  //實現run() 方法
 
        Looper.prepare();              //Looper線程準備階段
        mHandler = new Handler() {     //初始化消息處理器

            public vold handleMessage (Message msg) {
               //TODO :處理消息
            }
       
        };
        Looper.loop();                 //Looper線程循環階段
    }


}

 以上代碼可知,Looper線程實際上繼承了Thread 類,並實現run 方法,運行run()時:

1.調用Looper.prepare爲當前thread 創建一個Looper對象(一個線程有且僅有一個looper 對象);

2.創建handler對象,將之前創建的looper 對象的MsgQueue作爲自己的MsgQueue ,負責分發和處理消息;

3.調用Looper.loop()方法進入Looper線程循環階段;

4.handler 發送消息最後調用MessageQueue類中enqueueMessage函數,就是把消息插入到消息隊列中的合適位置

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章