context.getSystemService的简单说明

在android开发过程中这个方法一定不会陌生,比如我们在获取WindowManager和LayoutInflater对象的时候就需要我们调用这个方法。这个方法在context这个抽象类的一个抽象方法,《Context》简单说明这篇简单的博客中我们知道Activity,Servive等组建对应的Context这个接口的实现类是ContextImpl这个类。那么就让我们看看这个ContextImpl是怎么实现getSystemService这个方法的:

 private static final HashMap SYSTEM_SERVICE_MAP =
            new HashMap(); 
@Override
    public Object getSystemService(String name) {
        ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);
        //调用ServiceFetcher 提供的getService来获取name制定的对象
          return fetcher == null ? null : fetcher.getService(this);
    }

根据android Api我们可以知道name参数可以传递如下的参数:

context.getSystemService的简单说明_第1张图片

   可以看到在获取对应的对象的时候是从一个HashMap中获取的,该map的key就是getSystemServcie传入的name参数(参数列表见上图),而value是一个ServiceFetcher类型的对象。简单的说一些ServiceFetcher这个类,它是ContextImpl的一个静态内部类,该类提供一个createService方法,该方法只是简单的抛出一个异常,可以由子类具体实现其逻辑,同时提供了一个getServcie方法来从缓存中返回一个指定key对应的对象。同时ContextImpl里面还提供了一个ServiceFetcher的静态抽象子类StaticServiceFetcher,该子类为抽象类,提供了一个createStaticService抽象法方法,该方法返回一个Object对象。

   那么什么时候才初始化HashMap这个集合呢?ContextImpl这个类提供了一个registerService这个方法,用来把创建好的ServiceFetcher对象放入到SYSTEM_SERVICE_MAP这个map里面。该方法是静态方法,且是private的方法。从上图中我们知道SYSTEM_SERVICE_MAP里面存在这这些上图所示的key及其相关的Value,所以registerService这个方法毕竟得多次调用来将上图中的key及其对应的value对象放入map里面去,那么该方法在哪儿调用的呢?

  事实上在ContextImpl里面提供了一个静态语句块,来调用registerService方法,初始化上图的那些key对应的ServiceFetcher对象,我们知道静态语句块的初始化只执行一次:在虚拟机第一次加载该类的时候执行,且只执行一次。所以看看这个静态语句块都做了些神马(鉴于该语句块过长,所以省略了一部分):

static {
        registerService(ACCESSIBILITY_SERVICE, new ServiceFetcher() {
                public Object getService(ContextImpl ctx) {
                    return AccessibilityManager.getInstance(ctx);
                }});

        registerService(ACTIVITY_SERVICE, new ServiceFetcher() {
                public Object createService(ContextImpl ctx) {
                    return new ActivityManager(ctx.getOuterContext(), ctx.mMainThread.getHandler());
                }});

        registerService(ALARM_SERVICE, new StaticServiceFetcher() {
                public Object createStaticService() {
                    IBinder b = ServiceManager.getService(ALARM_SERVICE);
                    IAlarmManager service = IAlarmManager.Stub.asInterface(b);
                    return new AlarmManager(service);
                }});

        registerService(AUDIO_SERVICE, new ServiceFetcher() {
                public Object createService(ContextImpl ctx) {
                    return new AudioManager(ctx);
                }});
        //此处正是初始化LayoutInflater方法的地方,下面将简单分析
        registerService(LAYOUT_INFLATER_SERVICE, new ServiceFetcher() {
                //创建具体的LayoutInfalter对象
                public Object createService(ContextImpl ctx) {
                    return PolicyManager.makeNewLayoutInflater(ctx.getOuterContext());
                }});
     
        registerService(TELEPHONY_SERVICE, new ServiceFetcher() {
                public Object createService(ContextImpl ctx) {
                    return new TelephonyManager(ctx.getOuterContext());
                }});

        registerService(THROTTLE_SERVICE, new StaticServiceFetcher() {
                public Object createStaticService() {
                    IBinder b = ServiceManager.getService(THROTTLE_SERVICE);
                    return new ThrottleManager(IThrottleManager.Stub.asInterface(b));
                }});

       
        registerService(VIBRATOR_SERVICE, new ServiceFetcher() {
                public Object createService(ContextImpl ctx) {
                    return new SystemVibrator();
                }});

        registerService(WINDOW_SERVICE, new ServiceFetcher() {
                public Object getService(ContextImpl ctx) {
                    return WindowManagerImpl.getDefault(ctx.mPackageInfo.mCompatibilityInfo);
                }});

        。。。。。。。。。。
 }

到此为止SYSTEM_SERVICE_MAP里面的数据就初始化完毕,这就是我们可以调用getSystemService(name)获取系统对象的原因。因为之前的博客刚分析过LayoutInflater这个类(详见《Android解析xml简单分析》),所以文章最后就从这个它来做个简单的分析总结:

我们平时在Adapter中通过LayoutInflater的from静态方法来获取LayoutInflater,该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;
    }

事实上该法就是调用了文章开头所说的getSystemServcie方法:根据LAYOUT_INFLATER_SERVICE这个key,在上面所说的静态语句块中可以看出该对象的初始化:

 registerService(LAYOUT_INFLATER_SERVICE, new ServiceFetcher() {
                public Object createService(ContextImpl ctx) {
                    return PolicyManager.makeNewLayoutInflater(ctx.getOuterContext());
                }});
     
通过重写ServiceFetcher类的createService创建了LayoutInflater对象,然后在getSystemService方法中通过ServiceFetcher的getServcie方法获取出具体的LayoutInfalter对象。可以发现具体创建LayoutInflater对象的过程是在PolicyManager的makeNewLayoutInflater放方法里面完成的,至于PolicyManager的代码脉络分析详见 《WindowManager杂谈》这篇博文。
public PhoneLayoutInflater makeNewLayoutInflater(Context context) {
        return new PhoneLayoutInflater(context);
    }

从源码中可以看出makeNewLayout方法只是简单的返回了PhoneLayoutInflater这个对象。到此为止getSystemServcie的实现原理简单分析完毕现总结如下:

1)在Activity或者Service创建的时候初始化ContextImpl对象

2)ContextImpl类在第一次加载的时候,通过静态语句块初始化好相关的ServiceFetcher对象放入Map里面

3)取制定对象的时候,只需调用Context的getSystemServcie方法传入map对象的key就可以获取到需要的对象。

从文章开头我们可以知道getSystemServcie会调用getServcie来获取制定的对象,那么最后让我们看看这个方法的具体实现:

    public Object getService(ContextImpl ctx) {
            ArrayList 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 {
                  //再次获取相同的key或者name获取Service的时候,直接从缓存中获取
                   service = cache.get(mContextCacheIndex);
                    if (service != null) {
                        return service;
                    }
                }
                //第一次调用的时候需要调用具体的ServiceFetcher对象的createServcie来创建Servcie。
                service = createService(ctx);
                cache.set(mContextCacheIndex, service);
                return service;
            }
        }从该方法的实现中可以发现: 
  当我们第一次通过一个name获取指定的SystemServcie的时候,会调用ServcieFetcher的createServie来创建具体的ServiceObject(如PhoneLayoutInflater),然后将该ServcieObject放入到一个ArrayList缓存起来,当再次使用同一个name获取指定的ServcieObject的时候,直接从缓存中获取,避免对象的重复创建,这从某种程度上其实也是也达到了单例模式的效果。其实在第一次调用getSystemServcie的时候才初始化具体的服务对象,也起到了延迟初始化的效果。 
  

其实对getSystemService方法源码的分析总结,Android提供的这种实现方法或者思路完全根据需要模仿使用到自己的项目中去。到此结束对本博文,不当之处欢迎批评指正。

   


你可能感兴趣的:(android,小谈android)