android源码中的单例模式实现

源码中好多使用容器实现单例模式:

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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值