天天看點

Android 消息機制源碼分析

我們知道,當應用啟動的時候,android首先會開啟一個主線程,主線程管理ui控件,進行事件分發,當我們要做一個耗時的操作時,如聯網讀取資料,擷取讀取本地較大的檔案的時候,你應該在子線程中操作,因為有ui的更新,android主線程是線程不安全的,如果将更新界面放在子線程中是危險的,必須在主線程中執行,這個時候引出Handler,Handler運作在主線程,他與子線程通過message對象來傳遞資料.

Message類

Message類: 用來攜帶資料的載體
public int what; //辨別
public int arg1; //攜帶int類型資料
public int arg2; //攜帶int類型資料
public Object obj;//攜帶任意對象資料
long when; //儲存要被處理的時間點
Handler target; //處理消息的handler
Runnable callback; //處理消息的回調器對象
Message next; //用來儲存引用的下一個message(才能形成連結清單)
private static Message sPool; //存儲處理過的消息的池 //在需要Message對象時複用      
Message.obtain();//從消息池中擷取空消息對象      

說明:

1.我們要擷取空消息對象時最好通過Message.obtain()方法從消息池中取消息,而不是它的構造器,這樣可以更好的複用消息對象,以節約記憶體。

2.如果Message要攜帶int型的資料時,可以使用它的arg屬性

3.Message 中的target即為處理消息的handler

4.what 為辨別資訊類别

Handler類

sendMessage(Message msg);
sendEmptyMessage(int what);
sendMessageDelayed(Message msg, long delayMillis)
sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);//目前時間+延遲時間
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this; //處理消息Handler就是發送消息的handler
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis); //将消息添加到消息隊列中
}

public final void removeMessages(int what) {  //移除隊列中未被處理的消息
    mQueue.removeMessages(this, what, null);
}

public void dispatchMessage(Message msg) {
    if (msg.callback != null) { //如果message内部有回調處理器, 直接交給它處理
        handleCallback(msg);
    } else {
        if (mCallback != null) {//如果Handler内部有回調處理器, 交給它處理, 如果傳回true才結束, 否則繼續
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg); //調用Handler的回調方法處理
    }
}      

需要注意的是:

1.handler可以在任意線程發送消息,這些消息都将添加到MessageQueue中

2.handler實在關聯了looper的線程中處理消息的,當然主線程也是一個looper線程

MessageQueue

enqueueMessage(Message msg, long when) {
    msg.when = when; //将消息被處理的時間儲存在msg上

    //将msg對象儲存到mMessages連結清單中一個合适的位置

    nativeWake(mPtr); //喚醒處理等待狀态下的程式
    //不是通過wait()來實作的, 而是通過C/C++的代碼來實作的, 不會阻塞主線程
}

Message next() { //從消息隊列中取出需要處理的消息, 如果沒有進入等待狀态(沒有阻塞主線程)

}      

Looper

looper線程的建立

public class LooperThread extends Thread {
    @Override
    public void run() {
        // 将目前線程初始化為Looper線程
        Looper.prepare();

        ...

        // 開始循環處理消息隊列
        Looper.loop();
    }
}      

looper的一些屬性

public class Looper {
    private static final ThreadLocal sThreadLocal = new ThreadLocal();// 每個線程中的Looper對象其實是一個ThreadLocal
    
    final MessageQueue mQueue;// Looper内的消息隊列
    
    Thread mThread;// 目前線程      
private Looper() { // 建立Looper對象中的消息隊列,和它所屬的線程
    mQueue = new MessageQueue();
    mRun = true;
    mThread = Thread.currentThread();
}      

建立looper對象方法

public static final void prepare() {
    if (sThreadLocal.get() != null) {
       
        throw new RuntimeException("Only one Looper may be created per thread");
    }
    sThreadLocal.set(new Looper());
}      
static void loop() {
    final MessageQueue queue = me.mQueue; //拿到消息隊列
    Message msg = queue.next();// might block  從隊列中取出目前需要處理的消息

}
//将message對象交給handler分發處理
msg.target.dispatchMessage(msg);

msg.recycle(); //回收處理過消息: 清理内部資料, 并添加為消息池的第一個消息      

這樣我們就把消息隊列中的幾個重要的對象簡單的過了一邊。