美文网首页
(学习记录)Android源码设计模式解析与实战——第二章总结

(学习记录)Android源码设计模式解析与实战——第二章总结

作者: 等偓足够优秀 | 来源:发表于2018-08-28 20:48 被阅读0次

    单例设计模式

    单例设计模式的要点是单例,也就是说整个系统中只有一个实例对象,用于协调整个系统的资源和行为。适用于单例模式的场景有:
    1、一个对象的创建需要消耗巨大的资源,如ImageLoader。一个系统中创建多个这样的实例,整个系统都会吃不消了。
    2、用于控制系统全局的对象,用于协调整个提供的行为和资源。一个系统只需要一个控制者,正所谓一山不容二虎。

    如何创建单例模式

    1、饿汉式

    public class A {
         private static final A sInstance = new A(); 
    
        public static A getInstance() {
              return sInstance;
        }
    }
    

    饿汉式在类加载的时候就已经实例化了对象,即便是根本没有用到这个对象。只要import了这个类,那么这个对象就在系统中存在了。所以,这在某些场景下会存在一定程度的资源浪费。但是,如果设计了一个单例类,然而却没用到,这恐怕也是非常不合理的设计。饿汉式有个极大的优点,那就是对象实例化非常的简单直接,由于是通过ClassLoader加载类的时候实例化对象,同时又避免了多线程问题。

    2、懒汉式

    
    public class A {
        private static A sInstance;
        
        private A() {}
        
        public static A getInstance() {
            if (sInstance == null) {
                sInstance = new A();
            }
            
            return sInstance;
        }
    }
    

    懒汉式遵循的原则是用到时再实例化,与饿汉式刚好相反。秉承不浪费资源的原则,懒汉式似乎要优于饿汉式。其实不然,懒汉式的这种写法也存在弊端,那就是多线程问题。在复杂的并发环境下,sInstance很可能会被实例化多次。

    3、DCL模式

    public class A {
        private static A sInstance;
    
        private A() {}
    
        public static A getInstance() {
            if (sInstance == null) {
                synchronized (A.class) {
                    if (sInstance == null) {
                        sInstance = new A();
                    }
                }
            }
    
            return sInstance;
        }
    }
    

    DCL模式是专门用来解决懒汉式的多线程问题的,通过加锁的方式避免多线程的重入问题。这种方式在早期的JDK版本上也有可能存在问题,原因就是sInstance = new A()这行代码,编译器会先给sInstance赋值,然后再实例化A对象。这种情况下,另外一个线程可能检测到sInstance不为空进而直接使用这个对象,实际上这个对象还没有实例化完成。但是在高版本JDK上,SUN公司进行了优化,就不存在这个问题了.DCL模式是日常编码常用的一种实现单例的方式。

    好了,接下来看下Android源码中对单例模式的使用吧。

    Android源码中单例模式的使用

    Android源码中的单例模式实际上是很多的,Context有一个方法:

     @Override
        public Object getSystemService(String name) {
            return SystemServiceRegistry.getSystemService(this, name);
        }
    

    这个方法肯定很常用了,作用是获取系统服务。系统服务,顾名思义就是用来服务整个系统的,这刚好符合前面说的单例应用场景2。Wms、Pms这些服务在Android系统中都是以单例的形式存在的,这可以很方便的供系统中的App调用,前提是只要你有Context。

    接下来,我们来梳理一下Andorid中这些服务单例的初始化和使用,以LayoutInflater为例:

    1、服务的创建
    Context的实现是ContextImpl,我们先看ContextImpl的getSystemService方法:

    @Override
        public Object getSystemService(String name) {
            return SystemServiceRegistry.getSystemService(this, name);
        }
    
    private static final HashMap<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS =
                new HashMap<String, ServiceFetcher<?>>();
    public static Object getSystemService(ContextImpl ctx, String name) {
            ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
            return fetcher != null ? fetcher.getService(ctx) : null;
    }
    

    逻辑很简单有没有,就是从一个Map数组里把相应的服务给拿出来了。那我们看下服务是怎么放到HashMap里面的。

    static {
            registerService(Context.LAYOUT_INFLATER_SERVICE, LayoutInflater.class,
                    new CachedServiceFetcher<LayoutInflater>() {
                @Override
                public LayoutInflater createService(ContextImpl ctx) {
                    return new PhoneLayoutInflater(ctx.getOuterContext());
                }});
    
    }
    
    private static <T> void registerService(String serviceName, Class<T> serviceClass,
                ServiceFetcher<T> serviceFetcher) {
            SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
            SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
     }
    

    简单的理解,SystemServiceRegistry类在加载的时候会调用registerService方法将服务放进了HashMap中,后面等用到的时候再从数组中取出。

    2、LayoutInflater原理分析
    LayoutInflater的实现是PhoneLayoutInflater:

     private static final String[] sClassPrefixList = {
            "android.widget.",
            "android.webkit.",
            "android.app."
        };
     /** Override onCreateView to instantiate names that correspond to the
            widgets known to the Widget factory. If we don't find a match,
            call through to our super class.
        */
        @Override protected View onCreateView(String name, AttributeSet attrs) throws ClassNotFoundException {
            for (String prefix : sClassPrefixList) {
                try {
                    View view = createView(name, prefix, attrs);
                    if (view != null) {
                        return view;
                    }
                } catch (ClassNotFoundException e) {
                    // In this case we want to let the base class take a crack
                    // at it.
                }
            }
    
            return super.onCreateView(name, attrs);
        }
    

    这个类继承自LayoutInflater,重点是重写了onCreateView方法,作用是为每个View的路径添加前缀,类似android.widget.Button。这种添加前缀的方式很像装饰器设计模式,为LayoutInflater添加装饰功能。

    相关文章

      网友评论

          本文标题:(学习记录)Android源码设计模式解析与实战——第二章总结

          本文链接:https://www.haomeiwen.com/subject/gnoqwftx.html