Android設(shè)計(jì)模式(一)單例模式
參考內(nèi)容:《Android源碼設(shè)計(jì)模式與實(shí)戰(zhàn)》
android-sdk version:sdk29
代碼倉庫:https://github.com/kolibreath/Practices

單例模式主要需要滿足以下幾個特點(diǎn):
具有私有的構(gòu)造方法
需要滿足在多線程環(huán)境中單例的一致性
避免在反序列化時創(chuàng)建新的對象
單例模式有很多種寫法,我將它大體上分成三種:
使用鎖機(jī)制實(shí)現(xiàn):主要是滿足在多線程條件中單例的一致性
使用類加載機(jī)制:static關(guān)鍵字在其中扮演了重要的作用
特殊的形式:比如以enum、容器形式

使用類加載機(jī)制的單例模式
因?yàn)轭愒诩虞d的過程中會初始化其中的static成員,這樣在后續(xù)獲取單例的時候不會重新實(shí)例化新的成員;并且這個類加載一定先于多線程調(diào)用的環(huán)境,所以也可以避免多線程的影響。
使用類加載機(jī)制(static關(guān)鍵字)主要的三種單例模式:餓漢式、靜態(tài)內(nèi)部類
餓漢式
餓漢式就是在類加載時候馬上初始化類成員,立即加載,而不是延遲加載
靜態(tài)內(nèi)部類
靜態(tài)內(nèi)部類其實(shí)不像真正的【內(nèi)部類】,因?yàn)閮?nèi)部的語義不強(qiáng)。靜態(tài)內(nèi)部類在類加載的時候不會被初始化,更別說其中定義的靜態(tài)成員。在getInstance時才會加載靜態(tài)內(nèi)部類,這樣其中的靜態(tài)成員也會被延遲加載。相對于餓漢式好一點(diǎn)。
使用鎖機(jī)制的單例模式
這種方式主要是考慮多線程情況下,并且使用延遲加載的方式。
懶漢式單例模式
懶漢式單例模式使用synchronized保證一個時刻只能有一個線程調(diào)用這個方法,這樣內(nèi)部的new Singleton_lazy()一定是原子過程。但是這樣的方法很慢,線程需要阻塞排隊(duì)獲取synchronized鎖。
DCL單例模式
另外我們可以使用DCL避免在方法上加鎖,更細(xì)粒度的塊中加鎖。但是這種方法需要將單例寫為violatile變量。因?yàn)镴VM執(zhí)行指令可能會重排序,violatile保證new Singleton_DCL()的實(shí)例構(gòu)建,成員初始化對于其他線程都是可見的。
其他形式
使用枚舉
利用枚舉是天生線程安全的特性
使用容器
比如可以啟用一個Hashmap,如果沒有初始化,就將這個變量放入HashMap中。
我們通過Android sdk中LayoutInflater的初始化來說明這個問題。

單例模式在LayoutInflater系統(tǒng)服務(wù)中的應(yīng)用
我們通常使用Layout.from獲取一個LayoutInflater,然后會調(diào)用Context#getSystemService,返回一個LayoutInflater。
這里的Context實(shí)際上是ContextImpl,我們來看后續(xù)代碼:
ContextImpl在后面的過程中會去找到一個靜態(tài)hash容器,從容器中返回值。存儲在Hashmap中的服務(wù)只會在SystemServiceRegistry中加載一次:

對于LayoutInflater的補(bǔ)充說明
從上面可以看出,實(shí)際上是PhoneLayoutInflater完成的工作。具體我們以一個Activity解析xml的過程簡單說明一下問題:
Activity加載頁面的代碼在setContentView這塊,然后我們也知道getWindow返回的是PhoneWindow,我們通過查看PhoneWindoe#setContentView,發(fā)現(xiàn)里面和LayoutInflater相關(guān)的代碼只有如上一處。
LayoutInflater#inflate就是解析xml樹的過程,將其中的View進(jìn)行實(shí)例化,最終會調(diào)用到LayoutInflater#createViewFromTag:
這里分為對自定義View和android.widget中的View的解析,這兩個方法都會調(diào)用到createView。在createView中就是通過反射的方式構(gòu)建View的實(shí)例,具體的代碼我就不列出來了。值得說明的是creatView中也使用了HashMap緩存Constructor方法。
類似的使用容器同一管理單例的方法還可以再Retrofit中看到,比如管理ServiceMethod等。