1. 程式人生 > >Android 訊息機制原始碼分析

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(); //回收處理過訊息: 清理內部資料, 並新增為訊息池的第一個訊息

這樣我們就把訊息佇列中的幾個重要的物件簡單的過了一邊。