天天看點

《Android 源碼設計模式解析與實戰》——第2章,第2.7節Android源碼中的單例模式

本節書摘來自異步社群《android 源碼設計模式解析與實戰》一書中的第2章,第2.7節android源碼中的單例模式,作者 何紅輝 , 關愛民,更多章節内容可以通路雲栖社群“異步社群”公衆号檢視

2.7 android源碼中的單例模式

在android系統中,我們經常會通過context擷取系統級别的服務,如windowsmanagerservice、activitymanagerservice等,更常用的是一個layoutinflater的類,這些服務會在合适的時候以單例的形式注冊在系統中,在我們需要的時候就通過context的getsystemservice(string name)擷取。我們以layoutinflater為例來說明,平時我們使用layoutinflater較為常見的地方是在listview的getview方法中:

getview中使用的context對象的具體實作類是什麼呢?其實在application、activity、service中都會存在一個context對象,即context的總個數為activity個數 + service個數 + 1。而listview通常都是顯示在activity中,那麼我們就以activity中的context來分析。

我們知道,一個activity的入口是activitythread的main函數,在main函數中建立一個新的activitythread對象,并且啟動消息循環(ui線程),建立新的activity、新的context對象,然後将該context對象傳遞給activity。下面看看activitythread源代碼:

在main方法中,我們建立一個activitythread對象後,調用了其attach函數,并且參數為false。在attach函數中,參數為false的情況下(即非系統應用),會通過binder機制與activitymanager service通信,并且最終調用handlelaunchactivity函數,我們看看該函數的實作:

通過上面1~5注釋處的代碼分析可以知道,context的實作類為comtextimpl。我們繼續跟蹤contextimpl類:

從contextimpl類的部分代碼中可以看到,在虛拟機第一次加載該類時會注冊各種servicefatcher,其中就包含了layoutinflater service。将這些服務以鍵值對的形式存儲在一個hashmap中,使用者使用時隻需要根據key來擷取到對應的servicefetcher,然後通過servicefetcher對象的getservice函數來擷取具體的服務對象。當第一次擷取時,會調用servicefetcher的createservice函數建立服務對象,然後将該對象緩存到一個清單中,下次再取時直接從緩存中擷取,避免重複建立對象,進而達到單例的效果。這種模式就是小節中通過容器的單例模式實作方式,系統核心服務以單例形式存在,減少了資源消耗。

繼續閱讀