同事在进行code review的时候问到我context中的getSystemService方法在哪实现的,他看到了一个ClipBoardManager来进行剪切板存储数据的工具方法中用到了context.getSystemService(),而此处我使用的是Application级别的Context进行调用的,可IDE跳转时发现当前类中的getSystemService()方法居然是抽象的,Context类就是一个抽象类,没有具体的实现,可在进行调用的时候却一切正常,同事好奇该方法具体实现在哪实现的,于是我俩一起看源码和查资料后发现有几个值得注意的地方:
- 系统service获取和分享的问题,源码中提示到:
Note: System services obtained via this API may be closely associated with the Context in which they are obtained from. In general, do not share the service objects between various different contexts (Activities, Applications, Services, Providers, etc.)
大意: 获取的系统service可能和他们的context有紧密联系,一般来说不要在不同的context之间分享服务对象,如Activity、Application、Service、Provider
明显同样的方法调用的具体实现不同,从同样拥有getSystemService的Activity的实现可以看到,虽然最终调用还是从LayoutInflater的context获取
1 | /* |
通过super.getSystemService(name)跳转到ContextThemeWrapper这个Context.java类的代理类中,然而也并非是真正的具体实现,但是在此我们可以得知LayoutInflater实际上也是获取的是Application级别的全局context,因为该context也是该类中的mBase获取的😄:
1 |
|
1 | /* |
最后又追溯到了Context.java中的getSystemService(),什么情况呢,具体实现在哪??一番折腾后,找到了对应的Context实现类:ContextImpl.java
1 |
|
终于SystemServiceRegistry这个类中有了getSystemService的具体实现,调用的方法其实是getService(),这里三个方法很重要:
1 | /** |
可以看出三个方法对service进行了创建、获取和注册。而SystemServiceRegistry这个类负责创建、启动和管理所有的服务,当需要用到哪个服务的时候,调用到getService方法然后进行名字的索引来找到需要的服务,里面的关键元素:
- serviceFetcher
- IBinder,没错,实际上刚开始初始化的时候就是通过匿名内部类生成对应名字的服务,然后因为这些都是binder
在启动APP时进行了必备的service注册,关于注册的服务就不列举了太多了,结构大致如此:
1 | static { |
感兴趣的朋友可以自己看看,进行注册时候是通过HashMap的方式将服务的名字进行了索引存放。
上部分的代码中,可以看到有serviceFetcher相关的匿名内部类,每个服务对应了不同的实现,因此方法也是抽象的,下面是三个对应的静态抽象内部类和一个接口:
1 | /** |
我俩整个过程花了15分钟就了解了getSystemService的具体调用和实现的方式,还是源码来得快,在进阶Android开发过程中,阅读系统和三方类库的源码能够帮我们事半功倍的效果。