android笔记之SystemServiceRegistry

来源:互联网 发布:宁夏干部网络培训网 编辑:程序博客网 时间:2024/06/06 11:00

前言

    最近在看android源码中Window的内容,在看到WindowManagerImpl创建对象时发现了SystemServiceRegistry,这个类主要是用来缓存、注册、获取系统服务的。因为对它的缓存机制比较感兴趣,所以就研究下它的源码并记录下来,以便以后回顾迭代。

1. SystemServiceRegistry刚被导入内存时的分析

    先来看一段源码:

package android.app;final class SystemServiceRegistry {    //用来保存所有Service的名字    private static final HashMap<Class<?>, String> SYSTEM_SERVICE_NAMES =            new HashMap<Class<?>, String>();    //用来保存所有的ServiceFetcher,后面会拿出ServiceFetcher源码来说    //现在只要知道它是从缓存中拿Service,缓存中没有就创建Service就可以了    private static final HashMap<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS =            new HashMap<String, ServiceFetcher<?>>();    //记录缓存的大小    private static int sServiceCacheSize;    //注意构造方法是private的    private SystemServiceRegistry() { }    static{        //注册服务代码        registerService(Context.ACCESSIBILITY_SERVICE, AccessibilityManager.class,                new CachedServiceFetcher<AccessibilityManager>() {            @Override            public AccessibilityManager createService(ContextImpl ctx) {                return AccessibilityManager.getInstance(ctx);            }});        //注册服务代码        registerService(Context.CAPTIONING_SERVICE, CaptioningManager.class,                new CachedServiceFetcher<CaptioningManager>() {            @Override            public CaptioningManager createService(ContextImpl ctx) {                return new CaptioningManager(ctx);            }});        ...//大量类似的注册服务代码    }}

    在SystemServiceRegistry类刚被导入内存时,这些静态字段就会被初始化、静态字段就会被执行。SYSTEM_SERVICE_NAMES、SYSTEM_SERVICE_FETCHERS这两个字段不仅是静态的,还是final的,这说明这俩字段被初始化之后,对象就不能更改了但可以增删元素(因为是HashMap)。这两个字段,分别用来存储Service名字和获取Service实例的Fetcher对象的。

    SystemServiceRegistry的构造方法是私有的,说明它不能在类外创建对象,看一下该构造方法在类内的调用,发现也没有调用,这说明SystemServiceRegistry是不允许创建对象的。再看一下该类的其它方法和字段,发现都是静态的,这就可以确定SystemServiceRegistry类是被当做Util来使用的,并且不允许创建该类的实例。

    static代码块中大量调用了registerService方法,那就结合registerService方法的调用和声明来看一下:

...static{    ...    //registerService的调用    registerService(Context.WINDOW_SERVICE, WindowManager.class,                new CachedServiceFetcher<WindowManager>() {            @Override            public WindowManager createService(ContextImpl ctx) {                return new WindowManagerImpl(ctx);            }});    ...}...//registerService的声明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);}...

    先看一下registerService方法声明的参数:

参数 含义 serviceName service的名字,比如Context.WINDOW_SERVICE serviceClass 该Service对象的Class类,比如WindowManager.class serviceFetcher ServiceFetcher对象

    registerService方法内的逻辑很简单,就是以serviceClass为key将serviceName存储到SYSTEM_SERVICE_NAMES这个HashMap中,以serviceName为key将ServiceFetcher对象对象存储到SYSTEM_SERVICE_FETCHERS这个HaspMap中。

    下面看一下,ServiceFetcher的声明及其实现类CachedServiceFetcher。如上述代码所示,registerService方法被调用时传入的第三个参数即为CachedServiceFetcher的对象。

package android.app;final class SystemServiceRegistry {    ...    private static int sServiceCacheSize;    ...    static abstract interface ServiceFetcher<T> {        T getService(ContextImpl ctx);    }    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];                if (service == null) {                    service = createService(ctx);                    cache[mCacheIndex] = service;                }                return (T)service;            }        }        public abstract T createService(ContextImpl ctx);    }    ...}

    从代码结构来看,ServiceFetcher为SystemServiceRegistry类的静态内部接口,定义了getService方法;CachedServiceFetcher为SystemServiceRegistry类的抽象静态内部类,实现ServiceFetcher接口并实现其定义方法getService方法。

    另外,CachedServiceFetcher的构造方法被调用时会将此时SystemServiceRegistry类中静态成员变量sServiceCacheSize的值赋给其final的成员变量mCacheIndex,然后sServiceCacheSize加1。结合上述static代码块中大量调用registerService方法时大量new CachedServiceFetcher对象作为第三个参数可知,SystemServiceRegistry类中静态成员变量sServiceCacheSize其实就是用来记录static代码块中注册了多少个服务的。同时还保证了每一个注册的服务都有一个唯一的下标mCacheIndex(与其他注册服务的下标不同)记录在ServiceFetcher对象内。

说一个小知识点:类的成员final非静态变量如果未初始化,那其实是可以在该类的构造方法初始化的。比如说,这里的mCacheIndex。

    SystemServiceRegistry类被导入内存时,能执行到的差不多就是如上所说了:静态成员变量的初始化,静态代码块以及静态代码块中执行到的registerService方法和给registerService传递参数时执行到的CachedServiceFetcher类的构造方法。

    SystemServiceRegistry类一般只会导入内存一次,然后就留在内存里了。这样就保证了static代码块只会执行一次,注册各个服务也只各执行一次,获取服务的ServiceFetcher对象也是一个服务对应一个。

2. 使用SystemServiceRegistry提供的方法创建缓存并获取服务

    通过上述对registerService方法功能的分析可知,SystemServiceRegistry存储下来的只是service名字和获取该service的ServiceFetcher对象,并没有直接存储该Service实现类的对象。那SystemServiceRegistry的缓存是在什么时候创建的?Service实现类的对象又是什么创建并存入到缓存的呢?

    1. 创建缓存

    SystemServiceRegistry类的方法并不多,public修饰可被外界调用的也只有3个而已:createServiceCache、getSystemService、getSystemServiceName。根据方法名就很快找到了创建缓存的方法createServiceCache,下面具体看一下这个方法的声明:

public static Object[] createServiceCache() {    return new Object[sServiceCacheSize];}

    超级简单的一个方法,就创建了一个Object数组而已。上面已经解释了sServiceCacheSize的作用是记录注册的所有服务的个数,而此处使用sServiceCacheSize来作为缓存数组的长度。

    关于创建缓存还有一点要说的,查看createServiceCache方法被调用的地方,发现它只在初始化ContextImpl的一个成员变量时被调用了,其它地方没调用:

package android.app;class ContextImpl extends Context {    ...    final Object[] mServiceCache = SystemServiceRegistry.createServiceCache();    ...}

    从这里就可以看出,SystemServiceRegistry类中的缓存对象并没有设置到SystemServiceRegistry类中,而是存储到了另一个类ContextImpl的成员变量上了。这个跟ThreadLocal中的静态内部类ThreadLocalMap的实例对象并没有设置在ThreadLocal类中,而是设置在了Thread类的成员变量上多多少少有些相似。

    2. 获取Service实例

    上面说了,SystemServiceRegistry中可被外界调用的public方法很少,只有3个。上面说了用来创建缓存数组的createServiceCache方法,下面说一下用来获取Service实例的getSystemService方法:

public static Object getSystemService(ContextImpl ctx, String name) {    ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);    return fetcher != null ? fetcher.getService(ctx) : null;}

    也是超级简单的一个方法,从SystemServiceRegistry的静态且final的hashmap(SYSTEM_SERVICE_FETCHERS)中取出ServiceFetcher对象(ServiceFetcher对象在SystemServiceRegistry类被导入内存执行static代码块时已被初始化),然后调用其getService方法来获取Service实例。下面来看一下ServiceFetcher的实现类CachedServiceFetcher中的getService方法(CachedServiceFetcher类上面已经贴过,这里只贴出其方法getService):

@Override@SuppressWarnings("unchecked")public final T getService(ContextImpl ctx) {    //从ContextImpl对象中获得缓存数组    final Object[] cache = ctx.mServiceCache;    //某个线程正在获取Service,其他获取Service线程在这里阻塞    synchronized (cache) {        //一个下标对应一个Service,从缓存数组中获取该下标下的Service        Object service = cache[mCacheIndex];        //如果缓存数组中还没有Service就要去创建,创建好后保存到缓存数组的相应下标下        if (service == null) {            service = createService(ctx);            cache[mCacheIndex] = service;        }        //返回该服务        return (T)service;    }}public abstract T createService(ContextImpl ctx);

    这个getService的逻辑基本就是缓存数组中获取不到该服务就先去创建该服务,创建好后将该服务存储到缓存数组中并返回该服务。下面看一下CachedServiceFetcher类中的createService方法:

static abstract class CachedServiceFetcher<T> implements ServiceFetcher<T> {    ...    public abstract T createService(ContextImpl ctx);}

    该方法是抽象的,那该方法的具体实现在哪儿呢?其实在上述的static代码中new CachedServiceFetcher对象时在后面的大括号中已经实现了createService方法。比如静态代码块中注册窗口服务时是这样的:

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

    到此已经通过获取了Service实例。

总结

    这里作一个总结,以便对SystemServiceRegistry有一个整体的印象:

  • SystemServiceRegistry类中ServiceFetcher对象是复用的,不同的ContextImpl对象获取相同的Service实例使用的同一个ServiceFetcher对象;
  • 对Service缓存的数组是记录在ContextImpl中的,不同的ContextImpl对象缓存数组不同。
  • Service缓存数组初始大小即为要注册的所有服务的个数,但数组每个位置上的Service实例均为空。只有在调用SystemServiceRegistry的getSystemService方法时发现没这个Service实例才会去创建这个Service实例,并存储到缓存数组中,保证再次调用getSystemService方法时返回缓存数组中的该实例;
  • SystemServiceRegistry这种缓存机制的好处在于,不同ContextImpl对象使用不同的缓存数组,但不同的缓存数组获取相同的Service实例可以复用同一个ServiceFetcher对象;只在需要获取Service实例时才会去创建该Service实例,并保证以后需要时返回缓存中的该实例。
原创粉丝点击