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

那么就让我们看看这个ContextImpl是怎么实现getSystemService这种方法的:

 private static final HashMap<String, ServiceFetcher> SYSTEM_SERVICE_MAP =
            new HashMap<String, ServiceFetcher>();
@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參数能够传递例如以下的參数:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />

   能够看到在获取相应的对象的时候是从一个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<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 {
//再次获取同样的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提供的这样的实现方法或者思路全然依据须要模仿使用到自己的项目中去。到此结束对本博文。不当之处欢迎批评指正。

   

context.getSystemService的简单说明的更多相关文章

  1. 【Android】 context.getSystemService()浅析

    同事在进行code review的时候问到我context中的getSystemService方法在哪实现的,他看到了一个ClipBoardManager来进行剪切板存储数据的工具方法中用到了cont ...

  2. Android操作系统服务(Context.getSystemService() )

    getSystemService是Android很重要的一个API,它是Activity的一个方法,根据传入的NAME来取得对应的Object,然后转换成相应的服务对象.下面介绍系统相应的服务: 传入 ...

  3. 02 . Go开发一个日志收集平台之Context及etcd简单使用

    Context简单使用 context设置,获取value值 应用于全局通用参数传递 package main import ( "context" "fmt" ...

  4. [安卓] 18、一个简单的例子做自定义动画按钮和自定义Actionbar

    在做安卓UI的时候有时候需自定义具有动画效果的按钮或需要自定义一下actionbar~ 本节用一个简单的demo讲如何自定义具有动画效果的按钮,以及个性化的actionbar 下面是效果: 其中: △ ...

  5. Android ListView简单实用

    layout创建: activity_main.xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/ ...

  6. Android Context 是什么?

    andorid 开发(42)  版权声明:本文为博主原创文章,未经博主允许不得转载. [转载请注明出处:http://blog.csdn.net/feiduclear_up CSDN 废墟的树] PS ...

  7. 怎样在Android实现桌面清理内存简单Widget小控件

    怎样在Android实现桌面清理内存简单Widget小控件 我们常常会看到类似于360.金山手机卫士一类的软件会带一个widget小控件,显示在桌面上,上面会显示现有内存大小,然后会带一个按键功能来一 ...

  8. ExpandableListView简单应用及listview模拟ExpandableListView

    首先我们还是来看一些案例,还是拿搜狐新闻客户端,因为我天天上下班没事爱看这个东东,上班又没时间看新闻,上下班路途之余浏览下新闻打发时间嘛.           看这个效果挺棒吧,其实实现起来也不难,我 ...

  9. GlideDemo【Glide3.7.0版本的简单使用以及圆角功能】

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 本Demo主要记录Glide3.7.0版本的简单运用和实现圆角方案. 效果图 代码分析 Glide的centerCrop()和fit ...

随机推荐

  1. 完全背包模板 51Nod 1101

    N元钱换为零钱,有多少不同的换法?币值包括1 2 5分,1 2 5角,1 2 5 10 20 50 100元. 例如:5分钱换为零钱,有以下4种换法: 1.5个1分 2.1个2分3个1分 3.2个2分 ...

  2. Centos 7 JDK验证 解决java -version 报错: bash: /home/jdk1.8.0_161/bin/java: Permission denied

    2.vim /etc/profile  编辑profile  文件,在里面添加: #set java enviroment JAVA_HOME=/usr/java/jdk1.8.0_144 JRE_H ...

  3. 2018 java实训总结(时间戳&&主键)

    java实训题目:源管理系统. 答辩的时候被老师怼了以下几个的地方: 1.主键改变了 2.没时间戳却说自己的程序里有先后(这就是老师迂腐了,主键自增可以间接反馈出他加入的早晚,即使主键做出了改变但只是 ...

  4. IFC数据模式架构的四个概念层

    IFC模型体系结构由四个层次构成, 从下到上依次是 资源层(Resource Layer).核心层(Core Layer).交互层(Interoperability Layer).领域层(Domain ...

  5. BZOJ5332: [Sdoi2018]旧试题(莫比乌斯反演)

    时光匆匆,转眼间又是一年寒暑…… 这是小 Q 同学第二次参加省队选拔赛. 今年,小 Q 痛定思痛,不再冒险偷取试题,而是通过练习旧 试题提升个人实力.可是旧试题太多了,小 Q 没日没夜地做题,却看不到 ...

  6. Interrupt distribution scheme for a computer bus

    A method of handling processor to processor interrupt requests in a multiprocessing computer bus env ...

  7. hdoj-1870-愚人节的礼物(栈)

    愚人节的礼物 Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Sub ...

  8. java初始化过程中成员变量

    package day01; class Base{ int j; //1.j=0 Base(){ add(1); //2.调用子类add()方法 System.out.println(j); //4 ...

  9. 阅读笔记——Web应用程序

    Web应用程序与DD文件 Web应用程序 web应用程序是一种可以通过Web访问的应用程序.Web应用程序最大的好处是永和很容易访问应用程序.用户只需要有浏览器即可,不需要安装其他任何软件.一个Web ...

  10. Direct2D 图形计算

    D2D不仅可以绘制,还可以对多个几何图形对象进行空间运算.这功能应该在GIS界比较吃香. 这些计算包括: 合并几何对象,可以设置求交还是求并,CombineWithGeometry 边界,加宽边界,查 ...