簡析Handler、Looper和MessageQueue三者的關係

Android開發中,Handler用的非常多,因爲它和AsyncTask一樣是系統提供給我們的異步的通信機制。能夠將一些更新和別的不適合放在UI主線程的操作放到它們中去。

Handler的作用主要有兩個:一是在線程中發送消息, 二是獲取和處理消息。既可以發送消息sendEmptyMessage(int what) ,也可以發送指定的消息sendMessage(Message msg),還可以利用msg.obj的屬性去傳遞我們需要的參數甚至對象,使原本的通信機制更爲強大。


Handler發送消息的機制

Handler的出現,解決了在非UI主線程更新UI組件數據的問題。如上面提到的,我們使用handler.sendEmptyMessage(int what)  或者 sendMessage(Message msg)去發送消息,這個消息就會放去消息隊列MessageQueue中,MessageQueue是個先進先出的隊列,Handler按照這個順序一直從消息隊列MessageQueue中獲取消息Message,並且按照約定的方式去處理這些消息。下面是最簡單的發送空消息給handler去進行處理:

private Handler handler = new Handler(){
		@Override
		public void handleMessage(Message msg)
		{
			if(msg.what == 0x101)
			{	//約定如何處理不同的msg消息
				Log.i("print handler message", "msg.what = 0x101");
			}
			else if(msg.what == 0x201)
			{
				Log.i("print handler message", "msg.what = 0x201");				
			}
		}
	};
	
	/**
	 * 發送空消息
	 */
	private void sendMessageA()
	{
		handler.sendEmptyMessage(0x101);
	}
	
	private void sendMessageB()
	{
		handler.sendEmptyMessage(0x201);
	}
使用Handler的過程中,想必大家都會發現,如果在UI主線程中直接使用Handler去發送消息是沒問題的,但放在非主線程中就會報錯了。爲什麼呢?


Loop和MessageQueue的關係

這是因爲非主線程中並不會自動創建Looper對象。Looper是顧名思義,是一個“圈”,負責管理消息隊列MessgeQueue。Looper會不斷(一直循環到隊列中不再有message爲止)從MessageQueue中讀取消息並交給Handler去處理。因爲我們在主線程中handler發送消息,主線程是自動幫我們初始化創建一個Looper對象的,而且每個線程只能有一個Looper。因爲當然不允許同時有2個或以上的Looper對消息隊列讀取消息,這樣就會導致類似“鎖”的問題。也就是說,非UI主線程中,是不會自動幫我們創建這個Looper的。所以解決方法就是在發送消息前,先創建一個( prepare() ),然後開啓它( loop() )。這樣它才能正常的從消息隊列中讀取管理消息。


還是用上面的例子,不過改成在子線程中去創建Handler並且處理。

{
		private Handler mHandler;
		
		@Override
		public void run() {
			// 創建Looper
			Looper.prepare();
			mHandler = new Handler(){
				@Override
				public void handleMessage(Message msg)
				{
					if(msg.what == 0x101)
					{	//約定如何處理不同的msg消息
						Log.i("print handler message", "msg.what = 0x101");
					}
					else if(msg.what == 0x201)
					{
						Log.i("print handler message", "msg.what = 0x201");				
					}
				}
			};
			//啓動Looper,這樣它才能從消息隊列中讀取管理消息
			Looper.loop();
		}
	}
	
	private void sendMessgeInThread()
	{
		MessageThread mThread = new MessageThread();
		//創建Handler
		mThread.start();
		mThread.mHandler.sendEmptyMessage(0x101);
	}

總結三者的關係

從上面分個的來說明,我們已經知道Handler,Looper和MessageQueue分別的作用是什麼。這裏就總結下它們三者的關係:

情況一,在主線程中

創建Handler  ---->  使用handler發送消息  --->  消息被放入消息隊列MessageQueue中  ---->  (主線程自動創建的)Looper負責不斷地從消息隊列中取出消息,交給Handler --->  Handler再次對不同的消息進行處理  --->  消息message被處理完後,隨即被扔棄毀掉,然後繼續處理第二條到達的消息message,直到Looper已經將所有消息都讀取完。


情況二,在非主線程中

在上面的基礎上分別調用Looper.prepare() 和 Looper.loop()方法去創建和啓動Looer。創建Handler前調用Looper.prepare() ,創建完畢使用Looper.loop()。 剩下的收發消息和處理消息的過程和情況一是一樣的。



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