Android 源码解析:单例模式-通过容器实现单例模式-懒加载方式

本文分析了 Android 系统服务通过容器实现单例,确保系统服务的全局唯一。

  • 开发过 Android 的用户肯定都用过这句代码,主要作用是把布局文件 XML 加载到系统中,转换为 Android 的 View:
LayoutInflater layoutInflater = LayoutInflater.from(mContext);
  • 通过以上代码可以拿到 layoutflater 的对象, 然后通过 layoutInflater 就可以把 xml 文件转换为 View 加载到 activity 中,然后操作布局了,那么这个对象是怎么拿到的呢,跟源码。
  • from() 方法源码:
    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;
    }
  • 可以看到调用了很常见的一句代码: context.getSystemService(), 这句代码应该都用过,调用该方法,传入一个 Context 的常量,可以拿到相对于的 Manager 的对象
  • 经常见到的常量:
    • WINDOW_SERVICE: 获取 WindowManager 实例
    • LAYOUT_INFLATER_SERVICE: 获取 LayoutInflater 实例
    • ACTIVITY_SERVICE: 获取 ActivityManager 实例
    • ALARM_SERVICE: 获取 AlarmManager 实例
    • ...
  • 跟进 Context 类的这个方法, Context 是个抽象类,该方法是个抽象方法,源码如下:
public abstract class Context {
    ...
       public abstract Object getSystemService(@ServiceName @NonNull String name);
    ...
}
  • Context 类的实现类是 ContextImpl , 进入并查找这个方法,源码如下:
    @Override
    public Object getSystemService(String name) {
        return SystemServiceRegistry.getSystemService(this, name);
    }
  • 可以看到进入到了 SystemServiceRegistry 类,跟进看源码:
    public static Object getSystemService(ContextImpl ctx, String name) {
        ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
        return fetcher != null ? fetcher.getService(ctx) : null;
    }
  • SYSTEM_SERVICE_FETCHERS 是一个 HashMap ,keyStringvalueServiceFetcher<?>
    private static final HashMap<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS =
            new HashMap<String, ServiceFetcher<?>>();
  • ServiceFetcher<?> 是一个接口, 有一个方法,是获取 Service
    static abstract interface ServiceFetcher<T> {
        T getService(ContextImpl ctx);
    }
  • SystemServiceRegistry 源码
// 该类设计成 final 类,防止被继承了。
final class SystemServiceRegistry {
    private final static String TAG = "SystemServiceRegistry";

    // 注册的服务信息,存入到两个 HashMap 中。
    // 两个 HashMap 都是设置为静态的,初始化以后不会再变化的。
    private static final HashMap<Class<?>, String> SYSTEM_SERVICE_NAMES =
            new HashMap<Class<?>, String>();
    private static final HashMap<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS =
            new HashMap<String, ServiceFetcher<?>>();
    private static int sServiceCacheSize;

    // 私有构造方法
    private SystemServiceRegistry() { }

    // 静态代码块,第一次类加载的时候加载,且只加载一次,保证实例唯一
    static {
        registerService(Context.ACCESSIBILITY_SERVICE, AccessibilityManager.class,
                new CachedServiceFetcher<AccessibilityManager>() {
            // createService 该方法只会调用一次,在缓存数组中没有的情况下才会调用,剩下都是从缓存数组中获取的。
            @Override
            public AccessibilityManager createService(ContextImpl ctx) {

                // 调用每个 Manager 的初始化方法
                return AccessibilityManager.getInstance(ctx);
            }});

        registerService(Context.CAPTIONING_SERVICE, CaptioningManager.class,
                new CachedServiceFetcher<CaptioningManager>() {
            @Override
            public CaptioningManager createService(ContextImpl ctx) {
                return new CaptioningManager(ctx);
            }});

        registerService(Context.ACCOUNT_SERVICE, AccountManager.class,
                new CachedServiceFetcher<AccountManager>() {
            @Override
            public AccountManager createService(ContextImpl ctx) {
                IBinder b = ServiceManager.getService(Context.ACCOUNT_SERVICE);
                IAccountManager service = IAccountManager.Stub.asInterface(b);
                return new AccountManager(ctx, service);
            }});
        // 此处省略了N多的 registerService() 方法 
        ...
    }

    /**
     * 创建一个数组做缓存,把创建的 service 实例放入到该数组缓存起来
     * 该方法在
     */
    public static Object[] createServiceCache() {
        return new Object[sServiceCacheSize];
    }

    /**
     * 根据常量或者字符串获取指定服务
     */
    public static Object getSystemService(ContextImpl ctx, String name) {
        ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
        return fetcher != null ? fetcher.getService(ctx) : null;
    }

    /**
     * 通过 service 类 获取指定系统服务的名称,(这个方法好像没有用过)
     */
    public static String getSystemServiceName(Class<?> serviceClass) {
        return SYSTEM_SERVICE_NAMES.get(serviceClass);
    }

    /**
     * 在静态代码块中会调用到,添加 serviceName 和 serviceClass 到两个 HashMap 中。
     */
    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);
    }

    /**
     * Base interface for classes that fetch services.
     * These objects must only be created during static initialization.
     */
    static abstract interface ServiceFetcher<T> {
        T getService(ContextImpl ctx);
    }

    /**
     * 带有缓存的获取 service 抽象类,只要需要加载 service 的时候才初* 始化,相当于实现了单例模式的懒加载方式
     */
    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) {
                // 查找缓存,没有缓存的话,调用 createService() 初始化一个相关的 service
                Object service = cache[mCacheIndex];
                if (service == null) {
                    service = createService(ctx);
                    cache[mCacheIndex] = service;
                }
                return (T)service;
            }
        }
        // 实现类需要重写该方法,针对不同的 service 实现不同
        public abstract T createService(ContextImpl ctx);
    }

...

}
  • 该类上来就是一个静态代码块,在该类加载的时候,初始化了这个代码块,代码块中调用了静态方法 registerService() , 把各个 service 类通过键值对的形式存储到两个 HashMap 中,用户使用的时候,通过 key 获取到 HashMap 中的 ServiceFetcher, 然后调用 ServiceFetcher 的 getService() 方法获取到实例。该方法中,先从数组缓存中查找是否有实例,没有的话,调用 createService 方法,初始化该 service 类,并把该类实例放入到数组缓存中。下次用户再用的时候,会直接返回上次的唯一实例,实现了 Android 系统服务的单例模式。

思考

  • 针对项目的底层服务,需要提供大量单例的,可以采用容器和缓存的方式实现单例模式懒加载方式。通过该方式对项目进行重构和优化。
posted @ 2018-05-16 22:02  熠然  阅读(752)  评论(0编辑  收藏  举报