當(dāng)Android遇到單例模式

設(shè)計(jì)模式.png

定義

單例模式最初的定義出現(xiàn)于《設(shè)計(jì)模式》(艾迪生維斯理, 1994):“保證一個(gè)類僅有一個(gè)實(shí)例,并提供一個(gè)訪問它的全局訪問點(diǎn)?!?/p>

而我對(duì)單例的理解是,在可控的范圍內(nèi)充當(dāng)全局變量的作用,就相當(dāng)于C語言中一個(gè)全局結(jié)構(gòu)體。

一些資源管理器常常設(shè)計(jì)成單例模式。在計(jì)算機(jī)系統(tǒng)中,需要管理的資源包括軟件外部資源,譬如每臺(tái)計(jì)算機(jī)可以有若干個(gè)打印機(jī),但只能有一個(gè)Printer Spooler, 以避免兩個(gè)打印作業(yè)同時(shí)輸出到打印機(jī)中。每臺(tái)計(jì)算機(jī)可以有若干傳真卡,但是只應(yīng)該有一個(gè)軟件負(fù)責(zé)管理傳真卡,以避免出現(xiàn)兩份傳真作業(yè)同時(shí)傳到傳真卡中的情況。每臺(tái)計(jì)算機(jī)可以有若干通信端口,系統(tǒng)應(yīng)當(dāng)集中管理這些通信端口,以避免一個(gè)通信端口同時(shí)被兩個(gè)請(qǐng)求同時(shí)調(diào)用。

優(yōu)點(diǎn)

  • 由于單例模式在內(nèi)存中只有一個(gè)實(shí)例,減少了內(nèi)存開銷。
  • 單例模式可以避免對(duì)資源的多重占用,例如一個(gè)寫文件時(shí),由于只有一個(gè)實(shí)例存在內(nèi)存中,避免對(duì)同一個(gè)資源文件的同時(shí)寫操作。
  • 單例模式可以再系統(tǒng)設(shè)置全局的訪問點(diǎn),優(yōu)化和共享資源訪問。由于單例模式在內(nèi)存中只有一個(gè)實(shí)例,減少了內(nèi)存開銷。

實(shí)現(xiàn)

網(wǎng)上盛行的單例模式的多種寫法,而事實(shí)上,對(duì)于個(gè)人來說,我們只需要熟記自己喜歡的寫法就好了,而那些非延遲加載的,非線程安全的,同步鎖導(dǎo)致效率低的,沒必要再說怎么寫了。但是序列化與反序列化的問題,由于是否要考慮該問題,所以有以下解決方案

1. 內(nèi)部類方式(我最愛的方式)

內(nèi)部類SingletonHolder只有在getInstance()方法第一次調(diào)用的時(shí)候才會(huì)被加載,實(shí)現(xiàn)了延遲加載,而且其加載過程是線程安全的,但是序列化反序列化問題沒有解決

public class Singleton {

   private Singleton() { }
   
   private static class SingletonHolder {
      private final static Singleton INSTANCE = new Singleton();
   }
   
   public static Singleton getInstance() {
      return SingletonHolder.INSTANCE;
   }
   
   public void test(){
   }
}

使用
    Singleton.getInstance().test();

2.優(yōu)雅的枚舉方式

使用枚舉除了線程安全和防止反射強(qiáng)行調(diào)用構(gòu)造器之外,還提供了自動(dòng)序列化機(jī)制,防止反序列化的時(shí)候創(chuàng)建新的對(duì)象。因此,Effective Java推薦盡可能地使用枚舉來實(shí)現(xiàn)單列,但是在Android平臺(tái)上卻是不被推薦的
(PS:枚舉的原理并非想當(dāng)然的內(nèi)部靜態(tài)變量原理,[枚舉原理][1])

public enum Singleton {
    INSTANCE;
    private String name;
    public String getName(){
        return name;
    }
    public void setName(String name){
        this.name = name;
    }
}

Android中的應(yīng)用

如我們一開始說的,許多資源管理器設(shè)計(jì)成單例模式,那么我們的Android系統(tǒng)本身就有很多資源需要管理,最常見的是LayoutInflater 是單例模式,還有許多的manager,

(a) BluetoothOppManager
public class BluetoothOppManager {
    private static final String TAG = "BluetoothOppManager";
    private static final boolean V = Constants.VERBOSE;
    // 創(chuàng)建private static類實(shí)例
    private static BluetoothOppManager INSTANCE;

    /** Used when obtaining a reference to the singleton instance. */
    private static Object INSTANCE_LOCK = new Object();
    ...
    /**
     * Get singleton instance.
     */
    public static BluetoothOppManager getInstance(Context context) {
        synchronized (INSTANCE_LOCK) {
            if (INSTANCE == null) {
                INSTANCE = new BluetoothOppManager();
            }
            INSTANCE.init(context);

            return INSTANCE;
        }
    }
(b). InputMethodManager
public final class InputMethodManager {
    static final boolean DEBUG = false;
    static final String TAG = "InputMethodManager";

    static final Object mInstanceSync = new Object();
    static InputMethodManager mInstance;
    
    final IInputMethodManager mService;
    final Looper mMainLooper;
    
    /**
     * Retrieve the global InputMethodManager instance, creating it if it
     * doesn't already exist.
     * @hide
     */
    static public InputMethodManager getInstance(Context context) {
        return getInstance(context.getMainLooper());
    }
    
    /**
     * Internally, the input method manager can't be context-dependent, so
     * we have this here for the places that need it.
     * @hide
     */
    static public InputMethodManager getInstance(Looper mainLooper) {
        synchronized (mInstanceSync) {
            if (mInstance != null) {
                return mInstance;
            }
            IBinder b = ServiceManager.getService(Context.INPUT_METHOD_SERVICE);
            IInputMethodManager service = IInputMethodManager.Stub.asInterface(b);
            mInstance = new InputMethodManager(service, mainLooper);
        }
        return mInstance;
    }
}
(c) 數(shù)不勝數(shù)

...

謝謝大家閱讀,如有幫助,來個(gè)喜歡或者關(guān)注吧!


本文作者:Anderson/Jerey_Jobs

簡(jiǎn)書地址:[Anderson大碼渣][2]

github地址:[Jerey_Jobs][3]
[2]: http://www.itdecent.cn/users/016a5ba708a0/
[3]: https://github.com/Jerey-Jobs

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容