1. 程式人生 > >【原創】源碼角度分析Android的消息機制系列(一)——Android消息機制概述

【原創】源碼角度分析Android的消息機制系列(一)——Android消息機制概述

run 權限 開發 等待 通過 讀取 概述 走了 color

ι 版權聲明:本文為博主原創文章,未經博主允許不得轉載。

1.為什麽需要Android的消息機制

因為Android系統不允許在子線程中去訪問UI,即Android系統不允許在子線程中更新UI。

為什麽不允許在子線程中更新UI呢?因為Android的控件不是線程安全的。既然是非線程安全的,那麽若在多個子線程中並發訪問,UI控制可能會處於一種不可預期的狀態。有的讀者可能會說,為什麽不對UI控件加鎖呢?加鎖會降低UI訪問的效率,因為加鎖之後,若想要運行這段synchronized的代碼,線程要先拿到執行這段代碼的權限,Java裏面也即拿到某個同步對象的鎖,但是一個對象只有一把鎖,若此時這個同步對象的鎖被其他線程拿走了,那這個線程就只能先在等待隊列中等待了,而且當持有對象鎖的那個線程執行完,釋放對象鎖後,不一定會喚醒該線程,那麽該線程等待的時間也是未知的。這樣一來,就會導致訪問UI的效率很低。

Android的消息機制就是為了解決在子線程中訪問UI這一問題而誕生的。

2.何為Android的消息機制

Android的消息機制主要是指Handler的運行機制。

說到Handler,必然要提及另外三個概念,即Message、MessageQueue、Looper。而這四者的關系也常常是Android開發者在求職面試中經常被問及的一個問題。下面我們先簡單說明一下四者的作用以及關系,關於其實現原理,我們會在後續博文中詳細介紹。

Message:消息,當定義一個Message時,包含必要的描述和屬性數據。常用屬性:arg1arg2、what、obj、target等,其中arg1arg2可以存放整型數據,what可以用來標識一條Message,obj可以存放Object類型的任意對象,target就是處理一個Message的Handler。一般情況下,Message不需要new出來,可以調用handler的obtainMessage()方法獲取一個Message。

MessageQueue:消息隊列,其內部維護了一組消息,以隊列的形式對外提供了插入和讀取的操作。雖然名字為消息隊列,但其內部並非真正的隊列,而是采用了單鏈表的數據結構來存儲了消息列表。

Looper:循環,在此即消息循環,Looper並非簡單的循環,而是可以處理消息的。Looper會無限循環的去查找是否有新的消息,有的話,則處理消息,否則,就一直等待著。Looper中有一個比較特殊的概念,即ThreadLocal,其並非線程,而是在每個線程中存儲數據用的。線程默認是沒有Looper的,但是當ActivityThread(主線程,即UI線程)被創建時,就會初始化Looper。

Handler:可以將一個任務切換到某個指定的線程中去執行,一般可以用其更新UI。Handler創建的時候會采用當前線程的Looper來構造消息循環系統,Handler通過ThreadLocal可以獲取到當前線程的Looper,又因為ActivityThread在被創建的時候就初始化Looper了,所以在主線程中默認是可以使用Handler的。

Handler的運行需要MessageQueue和Looper的支撐,當Hanler創建完畢後,其內部的Looper和MessageQueue就可以和Handler一起協同工作了。Handlr可以通過兩種方式發送消息:①在不同線程之間,可以通過send方式發送;②在未來某個時間執行任務,可以用post方式,post方法將一個Runnable投遞到Handler的內部Looper中去處理,其實post方法最終也是通過send方法來完成的。

Handler的send方法被調用後,MessageQueue的enqueueMessage會將這個Message放到消息隊列中,Looper檢測到有新的消息到來了,就會去處理這個消息,最終消息中的Runnable或Handller的handlerMessage方法會被調用,消息被處理。而Looper是運行在創建Handler的線程中的,這樣一來,Handler中的業務邏輯就被切換到創建Handler所在的線程中去執行了。我們就可以在主線程中創建Handler,當我們在子線程處理任務並需要更新UI的時候,可以通過handler發送消息,回到主線程去更新UI。

【原創】源碼角度分析Android的消息機制系列(一)——Android消息機制概述