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方法声明的参数:
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实例,并保证以后需要时返回缓存中的该实例。
- android笔记之SystemServiceRegistry
- Android笔记之LoopViewPager笔记
- Android 笔记 之 Button
- Android 笔记 之 AutoCompleteTextView
- Android笔记之handler
- Android之学习笔记
- Android之Handler笔记
- android笔记之helloworld
- android笔记之autoCompleteTextView
- android笔记之布局
- Android笔记之数据库
- Android笔记之listView
- Android笔记之SQLite
- Android 之成长笔记
- Android笔记之屏幕分辨率
- Android 笔记之ScrollView
- Android笔记之Activity
- Android笔记之Service
- Webpack 达人的成长之路
- nowcoder 小AA的数列
- 可移动带分割线的GridView(空白项有分割线)
- hadoop中datanode不被namenode识别的问题
- 两个字符串拼接(不用strcat函数)
- android笔记之SystemServiceRegistry
- 内存溢出解决办法
- poi-tl 自定义图片处理类,解决生成多个文件时图片重复出现在word文档中问题
- 利用VisualEsxtop工具图形化查看esxtop参数
- 机器学习进阶路上不可错过的 28 个视频
- 行驶证OCR识别360度全面解析
- JVM深入学习总结
- tensorflow_rnn_cell_code
- EC Final 2015(Suffixes and Palindromes-差分约束)