android源码中的单例模式实现

来源:互联网 发布:该域名非本账户域名 编辑:程序博客网 时间:2024/05/18 01:16
源码中好多使用容器实现单例模式:public class Singleton {    private static Map<String, Object> objMap = new HashMap<String, Object>();    private Singleton() {    }    public static void registerService(String key, Object instance) {        if (!objMap.containsKey(key)) {            objMap.put(key, instance);        }    }    public static Object getService(String key) {        return objMap.get(key);    }}在程序的初始,将多种单例类型注入到一个统一的管理类中,在使用时根据key获取对象对应类型的对象.这种方式使得我们可以管理多种类型的单例,并且在使用时可以通过统一的接口进行获取操作,降低了耦合度.其实单例的核心原理都是,将构造函数私有化,并且通过静态方法获取一个唯一的实例,在这个获取中必须保证线程安全,防止反序列化导致重新生成实例对象等问题,android源码中的单例模式以常用的LayoutInflater为例:通常在代码中的使用如下:public static LayoutInflater from(Context context) {  //获取实例    LayoutInflater LayoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);    if (LayoutInflater == null) {        throw new AssertionError("LayoutInflater not found.");    }    return LayoutInflater;}可以看到from函数内部调用的是Context类的getSystemService(String key)方法,Context是一个抽象类,具体实现是在ContextImpl类中,class ContextImpl extends Context {    //通过SystemServiceRegistry类来具体实现    @Override    public Object getSystemService(String name) {        return SystemServiceRegistry.getSystemService(this, name);    }}//此类用来管理所有系统服务,可以用{@link Context#getSystemService方法来返回对应的服务final class SystemServiceRegistry {  static abstract interface ServiceFetcher<T> {        T getService(ContextImpl ctx);    }  //代码省略  //ServiceFetcher通过getService获取服务对象  static abstract class CachedServiceFetcher<T> implements ServiceFetcher<T> {        private final int mCacheIndex;        public CachedServiceFetcher() {            mCacheIndex = sServiceCacheSize++;        }    //获取系统服务        @Override        @SuppressWarnings("unchecked")        public final T getService(ContextImpl ctx) {            final Object[] cache = ctx.mServiceCache;            synchronized (cache) {                // Fetch or create the service.                Object service = cache[mCacheIndex]; //从缓存中读取service对象                if (service == null) {                    service = createService(ctx); //第一次创建该对象                    cache[mCacheIndex] = service; //该对象缓存到一个列表中                  }                return (T)service;            }        }        public abstract T createService(ContextImpl ctx); //子类复写该方法用以创建服务对象    }  //1. services 容器  private static final HashMap<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS =            new HashMap<String, ServiceFetcher<?>>();  private static int sServiceCacheSize;  //2. 注册服务器  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);    }    //3. 静态语句块 第一次加载该类时执行(只执行一次,确保实例的唯一性)  static {    //注册 LayoutInflater service        registerService(Context.NSD_SERVICE, NsdManager.class,                new CachedServiceFetcher<NsdManager>() {            @Override            public NsdManager createService(ContextImpl ctx) {                IBinder b = ServiceManager.getService(Context.NSD_SERVICE);                INsdManager service = INsdManager.Stub.asInterface(b);                return new NsdManager(ctx.getOuterContext(), service);            }});    }  //4. 根据key获取对应的服务    public static Object getSystemService(ContextImpl ctx, String name) {    //根据name来获取服务        ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);        return fetcher != null ? fetcher.getService(ctx) : null;    }    //代码省略}从以上代码中可以看到,在虚拟机第一次加载该类时,会注册各种ServiceFetcher,其中就包含了LayoutInflater service,将这些服务以键值对的形式存储在HashMap中,用户使用是只需要根据key来获取对应的ServiceFetcher,然后通过ServiceFetcher对象的getService函数来获取具体的服务对象,当第一次获取是会调用ServiceFetcher的createService函数创建服务对象,然后将该对象缓存到一个列表中,下次再取时直接从缓存中获取,避免重复创建对象,从而达到单例的效果.

2 0