• Android开发中无处不在的设计模式——单例模式


    对于开发人员来说,设计模式有时候就是一道坎,但是设计模式又非常有用,过了这道坎,它可以让你水平提高一个档次。而在android开发中,必要的了解一些设计模式又是非常有必要的。对于想系统的学习设计模式的同学,这里推荐2本书。一本是Head First系列的Head Hirst Design Pattern,英文好的可以看英文,可以多读几遍。另外一本是大话设计模式。

    这篇文章介绍一个模式,就是单例模式,因为个人觉得这个模式理解起来最容易,而且不是太复杂。

    首先了解一些什么是单例,从名字中就可以听出来就是在内存中维护唯一对象。这样做有以下几个优点

    • 对于那些比较耗内存的类,只实例化一次可以大大提高性能,尤其是在移动开发中。
    • 保持程序运行的时候该中始终只有一个实例存在内存中

    其实单例有很多种实现方式,但是个人比较倾向于其中1种。可以见单例模式

    代码如下

     
    public class Singleton {
        private static volatile Singleton instance = null;
    
        private Singleton(){
        }
    
        public static Singleton getInstance() {
            if (instance == null) {
                synchronized (Singleton.class) {
                    if (instance == null) {
                        instance = new Singleton();
                    }
                }
            }
            return instance;
        }
    }

    要保证单例,需要做一下几步

    • 必须防止外部可以调用构造函数进行实例化,因此构造函数必须私有化。
    • 必须定义一个静态函数获得该单例
    • 单例使用volatile修饰
    • 使用synchronized 进行同步处理,并且双重判断是否为null,我们看到synchronized (Singleton.class)里面又进行了是否为null的判断,这是因为一个线程进入了该代码,如果另一个线程在等待,这时候前一个线程创建了一个实例出来完毕后,另一个线程获得锁进入该同步代码,实例已经存在,没必要再次创建,因此这个判断是否是null还是必须的。

    至于单例的并发测试,可以使用CountDownLatch,使用await()等待锁释放,使用countDown()释放锁从而达到并发的效果。可以见下面的代码

     
    public static void main(String[] args) {
        final CountDownLatch latch = new CountDownLatch(1);
        int threadCount = 1000;
        for (int i = 0; i < threadCount; i++) {
            new Thread() {
                @Override
                public void run() {
                    try {
                        latch.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Singleton.getInstance().hashCode());
                }
            }.start();
        }
        latch.countDown();
    }

    看看打印出来的hashCode会不会出现不一样即可,理论上是全部都一样的。

    而在Android中,很多地方用到了单例。

    比如Android-Universal-Image-Loader中的单例

     
    private volatile static ImageLoader instance;
    /** Returns singleton class instance */
    public static ImageLoader getInstance() {
        if (instance == null) {
            synchronized (ImageLoader.class) {
                if (instance == null) {
                    instance = new ImageLoader();
                }
            }
        }
        return instance;
    }

    比如EventBus中的单例

     
    private static volatile EventBus defaultInstance;
    public static EventBus getDefault() {
        if (defaultInstance == null) {
            synchronized (EventBus.class) {
                if (defaultInstance == null) {
                    defaultInstance = new EventBus();
                }
            }
        }
        return defaultInstance;
    }

    上面的单例都是比较规规矩矩的,当然实际上有很多单例都是变了一个样子,单本质还是单例。

    如InputMethodManager 中的单例

     
    static InputMethodManager sInstance;
    public static InputMethodManager getInstance() {
        synchronized (InputMethodManager.class) {
            if (sInstance == null) {
                IBinder b = ServiceManager.getService(Context.INPUT_METHOD_SERVICE);
                IInputMethodManager service = IInputMethodManager.Stub.asInterface(b);
                sInstance = new InputMethodManager(service, Looper.getMainLooper());
            }
            return sInstance;
        }
    }

    AccessibilityManager 中的单例,看代码这么长,其实就是进行了一些判断,还是一个单例

     
    private static AccessibilityManager sInstance;
    public static AccessibilityManager getInstance(Context context) {
        synchronized (sInstanceSync) {
            if (sInstance == null) {
                final int userId;
                if (Binder.getCallingUid() == Process.SYSTEM_UID
                        || context.checkCallingOrSelfPermission(
                                Manifest.permission.INTERACT_ACROSS_USERS)
                                        == PackageManager.PERMISSION_GRANTED
                        || context.checkCallingOrSelfPermission(
                                Manifest.permission.INTERACT_ACROSS_USERS_FULL)
                                        == PackageManager.PERMISSION_GRANTED) {
                    userId = UserHandle.USER_CURRENT;
                } else {
                    userId = UserHandle.myUserId();
                }
                IBinder iBinder = ServiceManager.getService(Context.ACCESSIBILITY_SERVICE);
                IAccessibilityManager service = IAccessibilityManager.Stub.asInterface(iBinder);
                sInstance = new AccessibilityManager(context, service, userId);
            }
        }
        return sInstance;
    }

    当然单例还有很多种写法,比如恶汉式,有兴趣的自己去了解就好了。

    最后,我们应用一下单例模式。典型的一个应用就是管理我们的Activity,下面这个可以作为一个工具类,代码也很简单,也不做什么解释了。

     
    public class ActivityManager {
    
        private static volatile ActivityManager instance;
        private Stack<Activity> mActivityStack = new Stack<Activity>();
    
        private ActivityManager(){
    
        }
    
        public static ActivityManager getInstance(){
            if (instance == null) {
            synchronized (ActivityManager.class) {
                if (instance == null) {
                    instance = new ActivityManager();
                }
            }
            return instance;
        }
    
        public void addActicity(Activity act){
            mActivityStack.push(act);
        }
    
        public void removeActivity(Activity act){
            mActivityStack.remove(act);
        }
    
        public void killMyProcess(){
            int nCount = mActivityStack.size();
            for (int i = nCount - 1; i >= 0; i--) {
                Activity activity = mActivityStack.get(i);
                activity.finish();
            }
    
            mActivityStack.clear();
            android.os.Process.killProcess(android.os.Process.myPid());
        }
    }
    

    这个类可以在开源中国的几个客户端中找到类似的源码

    以上两个类是一样的,没区别。

  • 相关阅读:
    0149-函数可以做参数.abb
    0139-文件操作之二进制方式打开模式(一).abb
    0138-文件操作之基本打开模式.abb
    0130-实例之python实现随机验证码.abb
    0127-python内置函数(一).abb
    0126-lambda表达式.abb
    0113-全局变量和局部变量.abb
    函数的动态参数
    0103-深浅拷贝.abb
    0102-不同数据类型在内存中的存址方式
  • 原文地址:https://www.cnblogs.com/huoshenmanbu/p/4881393.html
Copyright © 2020-2023  润新知