2012年11月21日 星期三

Android - Process, Thread, MessageQueue and Looper 2013/09/24 Updated.

        當一個應用程式Process執行後,會啟動一個Thread來執行應用程式,該Thread稱之為Main Thread,Main Thread非常的重要,例如:調度事件到對應的Widget執行,像OnClick、OnKeyDown或drawing events 等,由於Main Thread也是跟Android UI toolkit(繼承android.widget和android.view)的Components(以下簡稱UI Toolkits)互動的主要Thread,所以我們也將Main Thread稱之為UI Thread。

        所有在同一個Process的Components,都會在UI Thread初次執行,並且Android會使用UI Thread來調度這些Components,例如;當使用者點擊螢幕上的按鈕,UI Thread就會調派Touch Event給對應的Button Widget (也就是改變Button壓下的狀態,並且將該事件佇列到event queue (Message Queue)),然後UI Thread再從event queue (Message Queue) 取出(透過Looper一個一個取出),通知widget進行畫面重畫並執行相對應的事件Callback。

        基於UI Thread的重要性,如果將UI Thread執行long-running的行為,例如:下載或者透過網路查詢資料等動作,勢必會使UI Thread無法分心其他事,甚至連drawing events也無法執行,更不用說Event調度等工作,如果UI Thread超過五秒沒反應時,系統會拋出application not responding (ANR) dialog,告知系統沒有回應,所以我們必須使用其它Thread來完成long-running的行為,這樣的Thread也稱為Worker Thread。

    因為UI Toolkits本身並沒有進行Thread-safe的設計,所以當Worker Thread要存取修改UI Toolkits時,要注意以下兩點規則:
  1. Do not block the UI thread
  2. 別透過UI Thread以外的Thread(Worker Thread)來直接存取UI Toolkits

         對於上述的第二點規則,必須要先瞭解Android的Thread架構,在Android系統中,一個Thread就有一個Message Queue,將所需的工作進行佇列,以便逐一取出執行,執行完再取出下一個執行,使其不會導致資源競用,而達成Thread-safe的狀態,但是要如何逐一取出使用,則必須要靠Looper來查看Message Queue中是否有尚未執行的訊息,而一個Thread中會有一個Looper來查看Message Queue的佇列狀態,如本人整理之投影片:


 



        而如果要更改UI Toolkits的狀態,則Worker Thread必須透過Handler將Message傳送到Message Queue,以等待Looper取出後交由Main Thread執行,如下圖:



轉貼請註明出處,最好直接使用聯結轉貼!Thanks~
作者: Samuel - 林靖傑
日期:2013/09/24