天天看點

Android設計模式-單例設計模式餓漢式懶漢式靜态内部類容器管理Activity管理類

文章目錄

  • 餓漢式
  • 懶漢式
  • 靜态内部類
  • 容器管理
  • Activity管理類

單例設計模式:

是一種最最常見的一種模式,保證整個程式中隻有一個執行個體,常用的場景一般都是一些特殊的類,比如:老闆,管理類等等(皮膚的管理,Activity的管理)。

套路:

  1. 構造函數私有,防止在外部 new 對象
  2. 内部必須提供一個靜态的方法,讓外部調用

餓漢式

/**
* 單例 - 餓漢式
*/
public class Singleton {
    //随着類的加載就已經new了對象
    private static Singleton mInstance = new Singleton();
    private Singleton(){

    }
    public static Singleton getInstance(){
        return mInstance;
    }
}
           

懶漢式

/**
 * 單例 - 懶漢式
 */
public class Singleton2 {
    //隻有使用的時候才去new對象(第一次調用getInstance時初始化),可能更加高效
//    private static Singleton2 mInstance = new Singleton2();
    private static Singleton2 mInstance;
    private Singleton2(){

    }
    public static Singleton2 getInstance(){
        if(mInstance == null){
            mInstance = new Singleton2();
        }
        return mInstance;
    }
}
           
public class Singleton3 {
    //但是 懶漢式單例模式 會有多線程并發問題,如果多線程調用還是會存在多個執行個體
    private static Singleton3 mInstance;
    private Singleton3() {

    }
    //雖說解決了線程安全的問題,但是又會出現效率的問題,
    //每次都要經過同步鎖的判斷,這種模式一般不建議使用
    public static synchronized Singleton3 getInstance() {
        if (mInstance == null) {
            mInstance = new Singleton3();
        }
        return mInstance;
    }
}
           
/**
 * Double Check Lock(DCL)
 * 
 * DCL方式實作單例模式的優點是既能夠在需要時才初始化單例,又能夠保證線程安全,
 * 且單例對象初始化後調用getInstance不進行同步鎖
 */
public class Singleton4 {
    private static Singleton4 mInstance;
    private Singleton4() {

    }
    public static Singleton4 getInstance() {
        if (mInstance == null) {
            synchronized (Singleton4.class) {
                if (mInstance == null) {
                    mInstance = new Singleton4();
                }
            }
        }
        return mInstance;
    }
}
           

問題:

  1. 開辟一塊記憶體空間
  2. 初始化對象
  3. 給變量指派,将mInstance對象指向配置設定的記憶體空間(此時mInstance就不是null了)

執行順序可能是1-2-3 ,也可能是1-3-2。 如果是後者,3執行完畢(mInstance不為null),2未執行(未初始化對象),此時切換到另一個線程B,因為mInstance不為null,線程B直接取走mInstance,再使用時就會出錯。

加上volatile 關鍵字

  • 防止重排序
  • 線程可見性 - 某一個線程改了公用對象(變量),短時間内另一個線程可能是不可見的,因為每一個線程都有自己的緩存區(線程工作區)
public class Singleton5 {
    private static volatile Singleton5 mInstance;
    private Singleton5() {

    }
    public static Singleton5 getInstance() {
        if (mInstance == null) {
            synchronized (Singleton5.class) {
                if (mInstance == null) {
                    mInstance = new Singleton5();
                }
            }
        }
        return mInstance;
    }
}
           

volatile 小例子

public class VolatileTest {
    public static void main(String[] args) {
        ThreadDemo td = new ThreadDemo();
        new Thread(td).start();
        while (true) {
            if (td.isFlag()) {
                System.out.println("------------------");
                break;
            }
        }
        // 執行結果? flag= true  ------------------
    }
}
class ThreadDemo implements Runnable {
    private volatile boolean flag = false;
    @Override
    public void run() {
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
        }
        flag = true;
        System.out.println("flag=" + isFlag());
    }
    public boolean isFlag() {
        return flag;
    }
    public void setFlag(boolean flag) {
        this.flag = flag;
    }
}
           

如果不加volatile,隻會輸出 “flag=true”

靜态内部類

靜态内部類單例模式

/**
 * 單例設計模式-靜态内部類
 * 
 * 隻有在第一次調用getInstance方法才導緻mInstance被初始化,
 * 是以第一次調用getInstance方法會導緻虛拟機加載SingletonHolder類,
 * 這種方式不僅能夠確定線程安全,也能夠保證單例對象的唯一性,同時也延遲
 * 了單例的執行個體化,這是推薦使用的單例模式實作方式
 */
public class Singleton5 {
    private Singleton5() {

    }
    public static Singleton5 getInstance() {
        return SingletonHolder.mInstance;
    }
    public static class SingletonHolder {
        private static final Singleton5 mInstance = new Singleton5();
    }
}
           

容器管理

/**
 * 單例設計模式 - 容器管理
 * 系統的服務就是使用這種
 */
public class Singleton6 {
    private static Map<String, Object> map = new HashMap<>();
    private Singleton6() {

    }
    public static void registerService(String key, Object instance) {
        if (!map.containsKey(key)) {
            map.put(key, instance);
        }
    }
    public static Object getService(String key) {
        return map.get(key);
    }
}
           

Activity管理類

實作方式有如下:

1 EventBus

2 廣播

3 集合管理

4 SingleTask

單點登入,彈框需要上下文,統一寫到BaseActivity中?

import android.app.Activity;

import java.util.Stack;

public class ActivityManager {

    private static volatile ActivityManager mInstance;
    // 集合用誰 List LinkedList Stack  ?? 删除和添加比較多
    private Stack<Activity> mActivities;

    private ActivityManager() {
        mActivities = new Stack<>();
    }

    // 雖說解決了線程安全的問題,但是又會出現效率的問題,
    // 即保證線程的安全同是效率也是比較高的
    // 這種方式其實還是會有問題?
    public static ActivityManager getInstance() {
        if (mInstance == null) {
            synchronized (ActivityManager.class) {
                if (mInstance == null) {
                    mInstance = new ActivityManager();
                }
            }
        }
        return mInstance;
    }

    /**
     * 添加統一管理
     */
    public void attach(Activity activity) {
        mActivities.add(activity);
    }

    /**
     * 移除解綁 - 防止記憶體洩漏
     */
    public void detach(Activity detachActivity) {
        // for 去移除有沒有問題? 一邊循環一邊移除會出問題 ,
        // 既然這個寫法有問題,自己又想不到什麼解決方法,參考一下别人怎麼寫的
        /*for (Activity activity : mActivities) {
            if(activity == detachActivity){
                mActivities.remove(activity);
            }
        }*/
        int size = mActivities.size();
        for (int i = 0; i < size; i++) {
            Activity activity = mActivities.get(i);
            if (activity == detachActivity) {
                mActivities.remove(i);
                i--;
                size--;
            }
        }
    }

    /**
     * 關閉目前的 Activity
     */
    public void finish(Activity finishActivity) {
        // for 去移除有沒有問題?
        /*for (Activity activity : mActivities) {
            if(activity == finishActivity){
                mActivities.remove(activity);
                activity.finish();
            }
        }
*/
        int size = mActivities.size();
        for (int i = 0; i < size; i++) {
            Activity activity = mActivities.get(i);
            if (activity == finishActivity) {
                mActivities.remove(i);
                activity.finish();
                i--;
                size--;
            }
        }
    }

    /**
     * 根據Activity的類名關閉 Activity
     */
    public void finish(Class<? extends Activity> activityClass) {
        // for 去移除有沒有問題?
        /*for (Activity activity : mActivities) {
            if(activity.getClass().getCanonicalName().equals(activityClass.getCanonicalName())){
                mActivities.remove(activity);
                activity.finish();
            }
        }*/

        int size = mActivities.size();
        for (int i = 0; i < size; i++) {
            Activity activity = mActivities.get(i);
            if (activity.getClass().getCanonicalName().equals(activityClass.getCanonicalName())) {
                mActivities.remove(i);
                activity.finish();
                i--;
                size--;
            }
        }
    }

    /**
     * 退出整個應用
     */
    public void exitApplication() {

    }

    /**
     * 擷取目前的Activity(最前面)
     */
    public Activity currentActivity() {
        return mActivities.lastElement();
    }
}