Android源码中的单例模式

来源:互联网 发布:黄惠康 知乎 编辑:程序博客网 时间:2024/06/05 20:47
在Android系统中,我们经常需要去通过context获取一些系统级别的服务。比如WindowManagerService、ActivityManagerService等。
最常用的莫过于LayoutInflater类,这些服务都是以单例的方式注入到系统当中的。

我们还是来以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内部调用的还是通过getSystemService方法去获取LayoutInflater.
那这个context又是什么呢?打开context发现它是一个抽象类。
通过阅读一些Google上的资料发现,其实Application、Activity、Service中都会存在Context对象,总数为Activity个数+Service个数+1,
Context是context家族最顶部的一级,其下还有很多实现类:
如图:


Context类本身是一个纯abstract类,它有两个具体的实现子类:ContextImpl和ContextWrapper。

ContextWrapper类,如其名所言,这只是一个包装而、已,ContextWrapper构造函数中必须包含一个真正的Context引
用,同时ContextWrapper中提供了attachBaseContext()用于给ContextWrapper对象中指定、真正的Context对象,调用ContextWrapper的方法都会被转向其所包含的真正的Context对象

 
ContextThemeWrapper类,如其名所言,其内部包含了与主题、(Theme)相关的接口,这里所说的主题就是指在AndroidManifest.xml中通过android:theme为Application元素或者Activity元素指定的主题。当然,只有Activity才需要主题,Service是不需要主题的,因为Service是没有界面的后台场景,所以Service直接继承于ContextWrapper,Application同理。

而ContextImpl类则真正实现了Context中的函数,应用程序中所调用的各种Context类的方法,其实现均来自于该类。

一句话总结:

Context的两个子类分工明确,其中ContextImpl是Context的具体实现类,ContextWrapper是Context的包装类。Activity,Application,Service虽都继承自ContextWrapper(Activity继承自ContextWrapper的子类ContextThemeWrapper),但它们初始化的过程中都会创建ContextImpl对象,由ContextImpl实现Context中的方法。


从这里我们可以知道,ContextImpl才是真正的起决定性作用的类:
ContextImpl是一个内部类,存在与ReceiverRestrictedContext类中

ReceiverRestrictedContext.java:

class ContextImpl extends Context {       public Object getService(ContextImpl ctx) {            ArrayList<Object> cache = ctx.mServiceCache;            Object service;            synchronized (cache) {                if (cache.size() == 0) {                    // Initialize the cache vector on first access.                    // At this point sNextPerContextServiceCacheIndex                    // is the number of potential services that are                    // cached per-Context.                    for (int i = 0; i < sNextPerContextServiceCacheIndex; i++) {                        cache.add(null);                    }                } else {                    service = cache.get(mContextCacheIndex);                    if (service != null) {                        return service;                    }                }                service = createService(ctx);                cache.set(mContextCacheIndex, service);                return service;            }         }}.....private static final HashMap<String, ServiceFetcher> SYSTEM_SERVICE_MAP = new HashMap<String, ServiceFetcher>();private static int sNextPerContextServiceCacheIndex = 0;//注册服务private static void registerService(String serviceName, ServiceFetcher fetcher) {if (!(fetcher instanceof StaticServiceFetcher)) {fetcher.mContextCacheIndex = sNextPerContextServiceCacheIndex++;}SYSTEM_SERVICE_MAP.put(serviceName, fetcher);}//根据key获取对应的服务@Overridepublic Object getSystemService(String name) {ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);return fetcher == null ? null : fetcher.getService(this);} static{...registerService(LAYOUT_INFLATER_SERVICE, new ServiceFetcher() {         public Object createService(ContextImpl ctx) {               return PolicyManager.makeNewLayoutInflater(ctx.getOuterContext());         }});...(这个静态语句块,在第一次加载该类时执行,里面包含了其他各种服务对象,可以自行googel看源码)}
从ReceiverRestrictedContext类的代码来看,在虚拟机第一次加载该类时会注册各种ServiceFatcher,其中就包含了LayoutInflater Serivce;系统将这些服务对象以键值对的形式存储在一个HashMap中,用户使用只需要根据key来获取到对应的ServiceFetcher,接着通过ServiceFecther对象的getService函数来获取具体的服务对象。当第一次获取的时候会通过ServiceFetcher的createService函数自动创建,然后将该对象缓存到一个列表中,下次再取直接从缓存中获取。以上就是用的是容器的方式来实现单例模式的。
参考书籍:
《Android源码设计模式解析与实战》

参考链接:

Context都没弄明白,还怎么做Android开发?

0 0
原创粉丝点击