Android 訊息機制原始碼分析
阿新 • • 發佈:2019-01-25
我們知道,當應用啟動的時候,android首先會開啟一個主執行緒,主執行緒管理ui控制元件,進行事件分發,當我們要做一個耗時的操作時,如聯網讀取資料,獲取讀取本地較大的檔案的時候,你應該在子執行緒中操作,因為有ui的更新,android主執行緒是執行緒不安全的,如果將更新介面放在子執行緒中是危險的,必須在主執行緒中執行,這個時候引出Handler,Handler執行在主執行緒,他與子執行緒通過message物件來傳遞資料.
Message類
Message類: 用來攜帶資料的載體 public int what; //標識 public int arg1; //攜帶int型別資料 public intarg2; //攜帶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(); //回收處理過訊息: 清理內部資料, 並新增為訊息池的第一個訊息
這樣我們就把訊息佇列中的幾個重要的物件簡單的過了一邊。