1. 程式人生 > 其它 >android 例項原始碼_設計模式(一):Android原始碼中的單例模式

android 例項原始碼_設計模式(一):Android原始碼中的單例模式

技術標籤:android 例項原始碼android 整合同一interface不同泛型android判斷是否登陸過android例項android例項原始碼android彈窗類的實現例項

什麼是單例模式?

單例模式(Singleton) 是最常見也最簡單的設計模式,它的目的就是在全域性只生成一個類的例項。

什麼場合用單例模式

應用中經常有多工進行資訊共享的需求,比如火車票售賣示例中,多個售票視窗其實共享一個票務池。如果一個票務池用一個類,那麼這個類就只能用一個例項,否則多工進行時會引起資源同步的問題。

另外,頻繁建立和銷燬的物件也可以用一個固定的例項,這樣的好處是節省記憶體重複建立和銷燬的開銷,提高程式的穩定性。

面向物件的程式設計很容易實現單例模型,比如 Java、C++ 等等,本文以 Java 程式碼講解。

單例模型的核心思想就是:私有化構造方法,只開放靜態的獲取方法。

640?wx_fmt=png

單例模式的實現手段(Java)

餓漢式

//餓漢式單例
publicclassSingletonHungry{

//主動建立靜態的私有例項
privatestaticSingletonHungrysingleton=newSingletonHungry();

//私有的構造方法
privateSingletonHungry(){}

//靜態的公開的例項獲取方法
publicstaticSingletonHungrygetInstance(){
returnsingleton;
}
}


餓漢式的例子一看就懂,不管三七二十一先建立了物件再說,不同的程序通過 getInstance 獲取的都是同一個物件,所以是執行緒安全的。

但也有個不好的地方就是,如果某個類建立過程會消耗很多資源,但程式執行中沒有呼叫過 getInstance 方法,那麼就存在資源浪費的情況,如果一個系統存在非常多此類情況那麼這個系統可能存在效能上的問題。

所以,我們需要一種延遲載入的功能。

懶漢式

publicclassSingletonLazy{
privatestaticSingletonLazyinstance;

privateSingletonLazy(){}

publicstaticSingletonLazygetInstance(){

if(instance==null){
instance=newSingletonLazy();
}
returninstance;
}
}


懶漢式在餓漢的基礎上做了改進,先判斷 instance 是否為空,如果為空則建立示例,否則直接返回。

懶漢式做到了延遲載入,非常適合單執行緒。

但多執行緒下面會存在問題,如果多個執行緒同時呼叫 getInstance 方法,可能存在同時判斷 instance 變數是否為空的情況,上面的程式碼中很容易導致重複建立多個例項,這違背了單例模式的目的。

一般而言,我們會進行一些同步手段。

雙檢鎖(DCL,double-checked locking)

publicclassSingletonDCL{
privatevolatilestaticSingletonDCLinstance;
privateSingletonDCL(){}
publicstaticSingletonDCLgetInstance(){
if(instance==null){
synchronized(SingletonDCL.class){
if(instance==null){
instance=newSingletonDCL();
}
}
}
returninstance;
}
}

DCL 進行兩次 instance 的判斷,並且利用了關鍵字 synchronized 。

試想當多個執行緒同時呼叫 getInstance 時,可能會存在同時判斷 instance 為空的情況。

但因為 synchronized 關鍵字的存在,同一個時刻只能一個執行緒進入程式碼同步區域,其它執行緒會被阻塞。

被阻塞的執行緒重新獲得進入程式碼臨界區時,再次判斷 instance 就好了。

靜態內部類

publicclassSingleton{
privatestaticclassSingletonHolder{
privatestaticfinalSingletonINSTANCE=newSingleton();
}
privateSingleton(){}
publicstaticfinalSingletongetInstance(){
returnSingletonHolder.INSTANCE;
}
}

這種方法也可以做到延遲載入,但是它又不同於餓漢式。

因為只有呼叫 getInstance 時,SingletonHolder 才會進行初始化。

之前做 Android 開發時,涉及到圖片快取載入的時候經常會看到一些開源元件有各類 ImageHolder 的程式碼,原理正是如此。

Android 原始碼中的單例模型

以 Android 系統版本為 9.0.0 程式碼為例,它的 framework 包中有一個 Singleton.java 檔案。

packageandroid.util;

/**
*Singletonhelperclassforlazilyinitialization.
*
*Modeledafterframeworks/base/include/utils/Singleton.h
*
*@hide
*/
publicabstractclassSingleton<T>{
privateTmInstance;

protectedabstractTcreate();

publicfinalTget(){
synchronized(this){
if(mInstance==null){
mInstance=create();
}
returnmInstance;
}
}
}


它是一個抽象類,並且支援泛型,從而支援模板化的形式建立任意型別的物件的單例。

原始碼很簡單,通過 DCL 實現了懶載入。

我們再看具體點。

xref: /frameworks/base/core/java/android/app/ActivityManager.java


/**
*@hide
*/
publicstaticIActivityManagergetService(){
returnIActivityManagerSingleton.get();
}

privatestaticfinalSingletonIActivityManagerSingleton=newSingleton(){@OverrideprotectedIActivityManagercreate(){finalIBinderb=ServiceManager.getService(Context.ACTIVITY_SERVICE);finalIActivityManageram=IActivityManager.Stub.asInterface(b);returnam;
}
};

ActivityManager 是 Android 最核心的系統服務之一,它的程式碼有 4000 多行,上面是部分程式碼。它通過一個隱藏的 getService 呼叫而建立。

建立過程就是通過上面的 Singleton實現。

從這個角度看,Android Framework 程式碼其實也不是很難是嘛,相信自己,你也可以寫出很多類似程式碼出來。


相關閱讀:

聊聊面向物件的6大設計原則

工作多年,我對架構的一些理解