每日Android源碼設計模式之-一、單例模式

單例設計模式是應用最廣的,它必須保證一個實例,例如一個ImageLoader實例,自行實例化并且向整個系統(tǒng)提供這個實例。

當創(chuàng)建一個對象的時候消耗過多,例如要訪問IO、數(shù)據(jù)庫資源等時使用。


特點

1.構(gòu)造函數(shù)不對外開放,private。

2.通過一個靜態(tài)方法或者枚舉返回單例類對象。

3.確保單例對象只有一個,特別是多線程。

4.確保在反序列化時不會重新構(gòu)建對象


分為兩種:

餓漢:類一創(chuàng)建就new對象出來。

懶漢:使用時候才去通過判斷對象是否為null來new新對象。


為了保證對象唯一,有幾種實現(xiàn)方法:

1.懶漢DCL(DoubleCheckLock)(一般能滿足需求)

雙重校驗同步代碼塊方法去new對象。

缺點:

高并發(fā)下,由于不是原子操作,可能會失效,

java5以后,可以在成員變量上加上volatile來禁止該對象上的讀寫指令重排序。


2.靜態(tài)內(nèi)部類單例模式: 推薦


3.枚舉單例 避免發(fā)序列化產(chǎn)生對象另類:容器實現(xiàn)單例模式

缺點:

接口擴展困難,

如果傳入的是Activity的context 很可能內(nèi)存泄露


4.使用容器來實現(xiàn)單例。


android源碼中的單例模式:

?我們常常通過context來獲取系統(tǒng)級別的服務,如WindowsManagerService、ActivityManagerService等,跟常用的是LayoutInflater類。

下面來分析下LayoutInflater

LayoutInflater.form(context)獲取單例->點進去也是調(diào)用了context.getSystemService(context.LAYOUT_INFLATER_SERVICE)

我們知道Activity對象和Context對象是在ActivityThread的main函數(shù)中生成的,找到main函數(shù)發(fā)現(xiàn)context是ComtextImpl.createActivityContext(this,r.pakageInfo,t.token)生成,然后通過activity.Attach傳入Activity中的。

最后來看ComtextImpl類

這里使用的使用容器實現(xiàn)單例模式。

容器:private static final HashMap<String,ServiceFetcher> SYSTEM_SERVICE_MAP = new ...;

//在ComtextImpl類static代碼塊中,會生成各種ServiceFatcher,然后存入SYSTEM_SERVICE_MAP中。

ComtextImpl類有一個getSystemService(String name)方法用來獲取存入SYSTEM_SERVICE_MAP中的ServiceFatcher對象,然后調(diào)用fetcher.getServiece(comtextImpl)方法。

fetcher中的getServiece方法從緩存ctxImpl.mServiceCache中獲取對象cache.get(mContextCacheIndex)避免重復創(chuàng)建。



我們?nèi)绾芜\用單例模式

例子:

ImageLoader使用DCL(Double checkLock)的方式來獲取對象

public static InmageLoadegetInstance(){

?if(sInstance ==null){

? ? synchronized(ImageLoader.class){

? ? ? i f(sInstance ==null){

? ? ? ? sInstance = new ImageLoader();

? ? ? }

? ? }

? }

}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內(nèi)容