Context的字面含义是上下文环境。应用的上层代码通过Context类提供的接口来操作Android的4大组件和资源。在Android的应用程序中,Context无处不在,很多接口都要求用Context对象作为参数。
Android的应用本质上是一个4大组件加上资源文件的容器,但是,这些组件的使用方式各不相同,而且比较复杂,Context类的作用就是把这些细节都封装起来,这样更方便开发人员使用它们。因此,可以把Context看作是整个框架的操作接口。
在Android应用中,从Context中派生的类的关系如下:
Context是一个抽象类,定义了接口,它的实现类是ContextImpl类。
ContextWrapper是Context的派生类,它实现了Context类的接口。但是ContextWrapper类所有方法的实现只是转调其成员变量mBase的方法。mBase本身也是Context对象,其类型是ContextImpl,因此,ContextImpl类才是Context类真正的实现。这种设计模式称为代理模式或包装者模式。这种设计模式的好处是把接口和实现分离,可以动态地切换多种实现。
ContextImpl类是Context的真正实现类,它集成了应用框架的一些核心对象,如ActivityThread对象。
Activity,Service,Application都是从ContextWrapper类派生出来的。Activity是通过ContextThemeWrapper类间接派生的,这样实现的目的是为了实现Activity中单独的Theme。一个应用中可以有一套全局的Theme,同时每个Activity还可以有自己的Theme。ContextWrapper类的成员变量中保存Theme资源和Resource资源。这样它的派生类Activity就能有独立的Theme。
Application的Context和Activity的Context的区别?
Activity、Service和Application这三种类型的Context都是可以通用的。不过有几种场景比较特殊,比如启动Activity,还有弹出Dialog。出于安全原因的考虑,Android是不允许Activity或Dialog凭空出现的,一个Activity的启动必须要建立在另一个Activity的基础之上,也就是以此形成的返回栈。而Dialog则必须在一个Activity上面弹出(除非是System Alert类型的Dialog),因此在这种场景下,我们只能使用Activity类型的Context,否则将会出错。
在应用程序中Context的具体实现子类就是:Activity,Service,Application。那么Context数量=Activity数量+Service数量+1。
Broadcast Receiver,Content Provider并不是Context的子类,他们所持有的Context都是其他地方传过去的,所以并不计入Context总数。
如何获取Context?
通常我们想要获取Context对象,主要有以下四种方法
1) View.getContext:返回当前View对象的Context对象,通常是当前正在展示的Activity对象。
2) Activity.getApplicationContext:获取当前Activity所在的(应用)进程的Context对象,通常我们使用Context对象时,要优先考虑这个全局的进程Context。
3) ContextWrapper.getBaseContext():用来获取一个ContextWrapper进行装饰之前的Context,可以使用这个方法,这个方法在实际开发中使用并不多,也不建议使用。
4) Activity.this:返回当前的Activity实例,如果是UI控件需要使用Activity作为Context对象,但是默认的Toast实际上使用ApplicationContext也可以。
5) getApplication()和getApplicationContext():它们得到的是同一个对象。getApplication()只能在Activity和Service中得到。在BroadcastReciver必须使用getApplicationContext()。