## Context学习
在平时的调用中,经常可以看见一个`Context`类型的对象作为参数传入Android各种组件中去。那么这个Context是个什么东西呢?
下面是我自己结合刚开始学习Android的经验,以及长期以来使用Android的经验和下面这篇博文所整理出来的想法。
> 参考:[认识一下Android里的Context](https://my.oschina.net/youranhongcha/blog/1807189)
### Context是什么?
首先看一下Context的中文释义:
> context: n. 上下文;语境;环境
很明显,Context在逻辑上表示一个运行期的“上下文”。只有在这个运行时期的上下文中,我们才可以进行一些系统操作,如获取资源、申请分配内存等。
那么为什么我在写其他java程序,或甚至是其他语言的时候没有很明显的感觉到Context的存在呢?
其实是有的,只是在进入程序之前(调用main函数之前),操作系统就已经给我们创建好了一个应用的上下文。所有的操作都是基于这一个上下文来的。
这里就是Android与其他程序很大的不同点。`在Android平台上,上下文的概念被再次细化了。`
在Android中经常会有这样的业务场景,一个应用程序只需要使用另一个程序的其中一个界面(Activity)。例如:在百度地图中查看到了一个感兴趣的饭店,想直接跳转至大众点评相对应饭店的详情页(不考虑这种调用是否能够成功)。如果在这种调用中需要启动一整个大众点评,无疑是十分耗时和耗费资源的。
那么安卓设计者是怎么解决这个问题的呢?Context细化就是他们设计的成果。在一个应用程序中,Application(代表一整个应用程序)、Activity、Service都是一个Context(实际上他们的确是继承了Context抽象类的)。
也就是说,除了程序以外,界面、服务他们都可以作为一个小的整体,具有一定的运行能力。这样,就很好解决上述业务场景的调用问题了。
说了这么多对Context应该也有了大概的理解了。下面举一个Context需要作为参数传入其他类中的例子。
Context的传递在UI逻辑层面见的比较多。如传递一个Context进行资源的获取等操作。
下面是RecyclerView.LayoutManager的一个实现类LinearLayoutManager中其中一个构造器:
```java
/**
* Creates a vertical LinearLayoutManager
*
* @param context Current context, will be used to access resources.
*/
public LinearLayoutManager(Context context) {
this(context, RecyclerView.DEFAULT_ORIENTATION, false);
}
```
这里很明确指出,Context是用来获取资源的。
再深层次探究一下,Context到底在哪里被用来获取资源了呢?
发现最后会被传递到LinearSmoothScroller来获取资源
```java
public LinearSmoothScroller(Context context) {
MILLISECONDS_PER_PX = calculateSpeedPerPixel(context.getResources().getDisplayMetrics());
}
```
现在这些源码的意思还看不太懂。希望如果以后还继续弄安卓的话,能够继续深究吧~
### Context组织模式
上面说到Activity和Service都是继承自Context的,那么在安卓中这个继承组织模式大概是怎么样的呢?
这里引用一下上面那篇网问的一张图
![](https://static.oschina.net/uploads/space/2018/0505/101457_1hNd_174429.jpg)
像我上面所说的,Application、Service和Activity都是Context的子类。同时他们内部还都持有一个自己的ContextImpl,由安卓系统提供。当这些子类需要访问应用资源或者系统服务时,就要把请求委托给内部的ContextImpl去实现了。
我们这里专注到Activity的继承链上来。发现在Context和Activity中间还包含了两个包装类。
> 上图中还有个ContextWrapper,该类是用于表示Context的包装类,它在做和上下文相关的动作时,基本上都是委托给内部mBase域记录的Context去做的。如果我们希望子类化上下文的某些行为,可以有针对性地重写ContextWrapper的一些成员函数。
这里就是设计模式——装饰者模式中的一个实践。通过一层层包裹,可以实现非常强大的组合。
> 但是其预想的调用行为一定是从最外层的ContextWrapper开始调用,然后逐层委托。这种结构最怕使用者不按常理出牌,从中间某个层次开始调用,那么执行起来的效果也许就不如你所愿了。
其中原文有个例子,由于我刚开始学Android还不太懂,这里就暂时不贴了
其次我们还注意到有一个Context的实现类ContextImpl
> 很明显,作为一个上下文的核心部件,ContextImpl有责任和更大的系统进行通信(我们可以把Android平台理解为一个大系统),所以它会有一个mMainThread成员。就以启动activity动作来说吧,最后会走到ContextImpl的startActivity(),而这个函数内部大体上是进一步调用mMainThread.getInstrumentation().execStartActivity(),从而将语义发送给Android系统。
> ContextImpl里的另一个重要方面是关于资源的访问。这就涉及到资源从哪里来。简单地说,当一个APK被加载起来时,系统会创建一个对应的LoadedApk对象,并通过解码模块将APK里的资源部分加载进LoadedApk。每当我们为一个上下文创建对应的ContextImpl对象时,就会从LoadedApk里获取正确的Resources对象,并记入ContextImpl的mResources成员变量,以便以后使用。
关于ContextImpl的一些细节实现,原文中也有,这里就不再赘述了。
【学习】Android中Context概念的学习笔记