Android系統中的消息處理Looper、Handler、Message

Android系統中消息處理

原理:
          Android系統中每個線程可以擁有唯一一個Looper實例,在Looper的構造函數中創建一個唯一的消息隊列MessageQueue,即MessageQueue對於線程來說也是唯一的。而Android應用在啓動的時候默認會爲主線程創建一個Looper實例,稱爲MainLooper,並藉助裏相關的Handler和Looper裏面的MessageQueue完成對Activity、Service、BroadcastReceiver等組件進行管理。而在子線程中,Looper需要顯示調用Looper.Prepare()創建實例。Prepare()通過ThreadLocal來保證這個Thread內只有一個Looper實例。
    

         Handler在創建的時候可以顯示指定Looper,這樣在Handler在調用sendMessage()投遞消息的時候會將消息添加到指定的Looper裏面的MessageQueue中區。如果不指定Looper,Handler默認綁定的是創建它的線程的Looper。

 

消息處理流程:
       (1) 包裝Message對象,指定Handler、回調函數Runnable callback、數據對象Object等
       

       (2) 調用Handler的sendMessage或post()投遞到Handler綁定的Looper對象的消息隊列MessageQueue
 

       (3) Looper對象的loop()方法通過循環不斷從MessageQueue取出消息進行處理
 

       (4) 調用Message綁定的Handler對象,即msg.target調用dispatchMessage()完成對消息的處理。

 

這裏在dispatchMessage()方法裏面,如何處理Message可以由用戶自己定義。

       1) 如果設置了Message的callback(Callback 實現了Runnable接口),則調用其run()函數進行消息的進行處理

 

       2) 如果設置了Handler裏面mCallback(實現了Callback接口的handleMessage),則由handleMessage()進行處理
 

       3) 最後才由繼承於Handler並實現了其handleMessage()方法的子類通過這個handleMessage()來處理

 

Message:    


           消息,就是線程間通信的數據單元,裏面可以封裝各種信息,Android系統中消息是通過Message類來封裝的。Message這個類實現了Parcelable接口,所以可以通過Intent或IPC傳遞。定義了一個能夠發送給Handler對象的消息,包含了消息的描述和任意數據對象。主要包含兩個int類型字段和一個Object類型字段。我們可以通過Message的構造函數生成一個消息,但是一般是通過調用Message.obtain()方法或Handler.obtainMessage()方法來構造一個消息。

 

public字段:
	public int what			// 用於自己的消息編碼,用來區分消息
	public int arg1		
	public int arg2
	public Object obj		// 發送給接收器的數據 
	public Messenger replyto	// 消息回覆的Messenger對象
	
	Bundle data;
	Handler target;			// 處理消息的目標Handler對象
	Runnable callback;		// 處理消息的回調
	
public方法:
	public Rnnable getCallback()
	public Bundle getData()
	public void setData(Bundle bundle)
	public void setTarget(Handler target)
	public Handler getTarget()	
	public void sendToTarget()
	public static Message obtain()
	public static Message obtain(Message orig)	// m.data = new Bundle(orig.data);
	public static Message obtain(Handler h)
	public static Message obtain(Handler h, Runnable callback)	// m.callback = callback;
	public static Message obtain(Handler h, int what)
	public static Message obtain(Handler h, int what, Object obj)
	public static Message obtain(Handler h, int what, int arg1, int atg2)
	public static Message obtain(Handler h, int what, int arg1, int arg2, Object obj) {
		Message m = obtain();
		m.target = h;
		m.what = what;
		m.arg1 = arg1;
		m.arg2 = arg2;
		m.obj = obj;
		return m;
	}
	

 

Handler:


         主要處理Message的類,負責將Message添加到消息隊列,以及對消息隊列中的消息進行處理。一般Handler的實例都是與一個線程和該線程的消息隊列一起使用,一旦創建了一個新的Handler實例,系統就把該實例與一個線程和該線程的消息隊列捆綁起來,這樣就可以發送消息和runnable對象給該消息隊列,並在消息隊列出口處理它們。
 兩個主要作用:1)安排消息或Runnable在某個線程中某個時間段執行。2)安排一個動作在另外一個線程執行。

class Handler {
// 內部接口:
	public interface Callback {
		public boolean handleMessage(Message msg)
	}
	
	final MessageQueue mQueue;
	final Looper mLooper;
	final Callback mCallback;
	IMessenger mMessenger;
	
	public void handleMessage(Message msg)		// 一般繼承Handler的類需要實現該方法

// 構造函數
	public Handler() {
		.....
		mLooper = Looper.myLooper()	// 獲取本線程的Looper對象
		mQueue = mLooper.mQueue;	// 直接將Looper對象的MessageQueue設置成自己的MessageQueue,這樣通過Handler發送消息的時候直接發送到Looper中去了
		mCallback = null;
	}
	
	// 帶Callback 的構造函數
	public Handler(Callback callback) {
		mLooper = Looper.myLooper();	//	使用當前線程的Looper對象
		mQueue = mLooper.mQueue;
		mCallback = callback;
	}
	
	public Handler(Looper looper) {		// 	使用參數傳入的Looper對象
		mLooper = looper;
		mQueue = looper.mQueue;
		mCallback = null;
	}

	public Handler(Looper looper, Callback callback) {	
		mLooper = looper;		// 	使用參數傳入的Looper對象
		mQueue = looper.mQueue;		
		mCallback = callback;		
	}
// obtain 消息
	public final Message obtainMessage(int what);
	public final Message obtainMessage(int what, Object obj)
	public final Message obtainMessage(int what, int arg1, int arg2)
	public final Message obtainMessage(int what, int arg1, int arg2, Object obj)
	public final Message obtainMessage() {
		return Message.obtain(this);
	}
	
// post 執行Runnable消息 
	public final boolean postAtTime(Runnable r, long uptimeMillis);
	public final boolean postAtTime(Runnable r, Object token, long uptimeMillis);
	public final boolean postDelayed(Runnable r, long delayMillis);
	public final boolea postAtFrontOfQueue(Runnable r)
	public final boolean post(Runnable r)	{
		sendMessageDelayed(getPostMessage(r), 0);
	}
	注意:
	private final getPostMessage(Runnable r) {
		Message m = Message.obtain();	// 這個時候生成的Message的target = null
		m.callback = r;	// 最後在dispatchMessage的時候調用這個 r.run()函數
		return m;
	} 
	
// send 消息
	public final boolean sendMessageAtFrontOfQueue(Message msg)	// 投遞到消息隊列開頭
	public final boolean sendMessageDelayed(Message msg, long delayMillis)	// 相對時間
	public final boolean sendMessage(Message msg)			// 投遞消息到隊列末尾
	public final boolean sendEmptyMessage(int what)			// 投遞空的消息
	public boolean sendMessageAtTime(Message msg, long uptimeMillis) {	// 投遞一個uptimeMillis時執行的消息
		MessageQueue queue = mQueue;
		if(queue != null) {
			msg.target = this;
			return queue.enqueueMessage(msg, uptimeMillis);	// 添加消息
		}
	}
	
// dispatch 消息
	public void dispatchMessage(Message msg) {	
		if(msg.callback != null) {
			handleCallback(msg);	// 調用的是 msg.callback.run()
		} else {
			if(mCallback != null) {
				mCallback.handleMessage(msg);	// 使用繼承與內部接口Callback的處理函數
				return;
			}
			handleMessage(msg);	// 最後才調用子類實現的handleMessage()函數
		}
	}
}


 

Looper: 


         Looper的主要作用就是循環迭代MessageQueue,默認情況下沒有跟線程相關聯的消息循環,必須在線程中調用prepare()方法,運行循環。但是在我們的Activity的Main()函數中,系統默認調用了
所以我們可以通過getMainLooper()獲得一個MainLooper。

public class Looper {
	
	static final ThreadLocal<Looper> sThreadLocal =  new ThreadLocal<Looper>();
	final MessageQueue mQueue;	// 消息隊列
	final Thread mThread;		// 線程對象
	volatile boolean mRun;		
	private static Looper mMainLooper = null;

	public static void prepare() {	// 往TLS中設置一個Looper對象,一個線程只能設置一個Looper
		return sThreadLocal.set(new Looper());
	}
	
	public static Looper myLooper() { 	// 獲取當前線程的Looper對象
		return sThreadLocal.get();
	}
	
	public static void prepareMainLooper() {
		prepare();
		setMainLooper(myLooper());	// mMainLooper = looper; 設置MainLooper
		myLooper().mQueue.mQuiotAllowed = false;	// MainLooper的mQuitAlloweed爲false不允許退出
	} 
	
	// 主循環
	public static void loop() {
		Looper me = myLooer();
		MessageQueue queue = me.mQueue;
		while(true) {
			Message msg = queue.next(); // 獲取消息隊列中的一個消息,可能會阻塞
			if(msg.target == null) {
				return;
			}
			msg.target.dispatchMessage(msg);	// 分發消息,調用Handler.dispatchMessage()
			msg.recycle();	// free消息
		}
	}
	public static MessageQueue myQueue() {
		return myLooper().mQueue;
	}
	
	// 構造方法
	private Looper() {
		mQueue = new MessageQueue();
		mRun = true;
		mThead = Thread.currentThread();
	}
	
	public void quit() {
		Message msg = Message.obtain();
		mQueue.enqueueMessage(msg, 0);	// msg->target = null 這是一個退出消息
	}	
}


 

           一般我們可以在一個線程A中創建一個Looper對象,並在run()方法中調用Looper.loop()開啓消息循環。然後在另外一個線程B中創建一個Handler並綁定到A線程的Looper實例。這樣當我們在B線程中投遞消息的時候會在A線程中進行處理。如果不指定Looper則默認是用當前線程的Looper進行處理。如下所示:

class MyThread extends Thread {
	public Looper myLooper = null;
	
	public void run() {
		Looper.prepare();
		myLooper = Looper.myLooper();
		Looper.loop();	// 進入循環
	}
}

{ 線程2中:
	MyThread thread = new MyThread();
	thread.start();	// 啓動線程
	Handler handler = new Handler(thread.myLooper);	// 使用上面線程的Looper對象
	handler.sendMessage();
}

        但是我們發現這樣很容易出現問題:線程2中使用的Looper對象時在線程1中創建的,雖然是在線程2中使用這個Looper之前創建的線程1,但是系統並不能保證我們在使用之前線程1中Looper對象已經創建好了,有可能此時線程1的Looper對象還沒有創建好,這樣我們在線程2中使用的就是一個Looper就是一個null。

        對此Android系統爲我們提供了一個特殊的HandlerThread完美的結局了這個問題:

public class HandlerThread extends Thread {
	public Looper getLooper() {
		...
		synchronized(this) {
			while(isAlive() && mLooper == null) {
				wait();	// 等待線程創建好Looper對象
			}
		}
	}
	public void run() {	
		...
		Looper.prepare();	// 創建Looper對象
		synchronized (this) {
			mLooper = Looper.myLooper();
			notifyAll();	// 通知獲取Looper的線程,Looper已經創建好
		}
		....
		Looper.prepare();	// 進入循環
	}
}

 

        下一章我們再分析MessageQueue,消息具體是如何投遞到消息隊列?Looper又是具體如何從MessageQueue獲取消息的即MessageQueue.next()具體是怎麼實現的? 

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