Android中的何为Context

在简书上看到的一篇文章,文章链http://www.jianshu.com/p/94e0f9ab3f1d 
讲述的特别好,以此作的一篇学习笔记。

Android 应用模型 是基于组件的设计模式,Android中的每个组件运行都需要一个完整的Android工程环境,只有在这个环境下,Android的组件:Activity,Service等系统组件才能够正常工作。这些组件并不能采用普通的Java对象的创建方式,即通过new进行实例化,而是需要各自的上下文环境(Context)。
Context是维持Android程序中各个组件正常工作的核心功能类。
Android程序猿把“场景“抽象成Context类,用户和操作系统的每一次交互都是一个场景。例如打电话,发短信都是有界面的场景,还有一些没有界面的场景,例如后台运行的服务(Service)。
一个应用程序可以看作一个工作环境,用户在这个环境中切换到不同的场景,这就像是一个前台秘书,他可能需要接待顾客,打印文件,还有可能接听用户电话,这些称之为不同的场景,前台秘书可以称之为应用程序。
一个Android应用程序,可以理解成一部电影或者一部电视剧,Activity,Service,Broadcast Receiver,Content Provider这四大组件就好比是这部戏里的四个主角。摄像机镜头就相当于是Context,只有通过摄像机(Context)才能将信息传递给用户。因此,四大组件必须工作在Context环境下才可以。Button,TextView,LinearLayout这些控件好比戏里的配角或者说群众演员,他们显然没有这么重用,随便一个路人甲路人乙都能演(可以new一个对象),但是他们也必须要面对镜头(工作在Context环境下)。
/**
 * Interface to global information about an application environment.  
 * This is an abstract class whose implementation is provided by the 
 * Android system.  
 * It allows access to application-specific resources and classes, as well as
 * up-calls for application-level operations such as launching activities,
 * broadcasting and receiving intents, etc.
 */
Context是一个抽象类,其子类及其关系如下:

这里写图片描述

Context类本身是一个纯abstract类,它有两个具体的实现子类:ContextImpl和ContextWrapper。
ContextWrapper类,如其名所言,这只是一个包装而已,ContextWrapper构造函数中必须包含一个真正的Context引用,同时ContextWrapper中提供了attachBaseContext()用于给ContextWrapper对象中指定真正的Context对象,调用ContextWrapper的方法都会被转向其所包含的真正的Context对象。ContextThemeWrapper类,如其名所言,其内部包含了与主题(Theme)相关的接口,这里所说的主题就是指在AndroidManifest.xml中通过android:theme为Application元素或者Activity元素指定的主题。当然,只有Activity才需要主题,Service是不需要主题的,因为Service是没有界面的后台场景,所以Service直接继承于ContextWrapper,Application同理。
而ContextImpl类则真正实现了Context中的所以函数,应用程序中所调用的各种Context类的方法,其实现均来自于该类。一句话总结:Context的两个子类分工明确,其中ContextImpl是Context的具体实现类,ContextWrapper是Context的包装类。Activity,Application,Service虽都继承自ContextWrapper(Activity继承自ContextWrapper的子类ContextThemeWrapper),但它们初始化的过程中都会创建ContextImpl对象,由ContextImpl实现Context中的方法。
程序中Context的数量:
    Context数量 = Activity数量+Service数量+1
Broadcast Receiver,Content Provider并不是Context的子类,他们所持有的Context都是其他地方传过去的,所以并不计入Context总数。
Context的使用限制:
由于Context的具体实例是由ContextImpl类去实现的,因此在绝大多数场景下,Activity、Service和Application这三种类型的Context都是可以通用的。
但是在启动Activity以及Dialog时,出于安全的考虑,Android不允许Activity以及Dialog凭空出现,一个Activity的启动必须要建立在另一个Activity的基础之上,也就是以此形成的返回栈。而Dialog则必须在一个Activity上面弹出(除非是System Alert类型的Dialog),因此在这种场景下,我们只能使用Activity类型的Context,否则将会出错。

这里写图片描述

Activity所持有的Context的作用域最广,无所不能。因为Activity继承自ContextThemeWrapper,而Application和Service继承自ContextWrapper,很显然ContextThemeWrapper在ContextWrapper的基础上又做了一些操作使得Activity变得更强大。
1:如果我们用ApplicationContext去启动一个LaunchMode为standard的Activity的时候会报错android.util.AndroidRuntimeException: Calling startActivity from outside of an Activity context requires the **FLAG_ACTIVITY_NEW_TASK** flag. Is this really what you want?这是因为**非Activity类型的Context并没有所谓的任务栈,所以待启动的Activity就找不到栈了。解决这个问题的方法就是为待启动的Activity指定FLAG_ACTIVITY_NEW_TASK标记位,这样启动的时候就为它创建一个新的任务栈,而此时Activity是以singleTask模式启动的。**
所有这种用Application启动Activity的方式不推荐使用,Service同Application。
2:在Application和Service中去layout inflate也是合法的,但是会使用系统默认的主题样式,如果你自定义了某些样式可能不会被使用。所以这种方式也不推荐使用。
凡是跟UI相关的,都应该使用Activity做为Context来处理;其他的一些操作,Service,Activity,Application等实例都可以,当然了,注意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也可以。
getApplication()和getApplicationContext()
两者获取的内存地址是一样的,也就是两者是同一个对象。
Application本身就是一个Context,所以这里获取getApplicationContext()得到的结果就是Application本身的实例。
二者区别:
getApplication()方法的语义性非常强,一看就知道是用来获取Application实例的,但是这个方法只有在Activity和Service中才能调用的到。那么也许在绝大多数情况下我们都是在Activity或者Service中使用Application的,但是如果在一些其它的场景,比如BroadcastReceiver中也想获得Application的实例,这时就可以借助getApplicationContext()方法了。
public class MyReceiver extends BroadcastReceiver{
    @Override
    public void onReceive(Context context, Intent intent){
        Application myApp=(Application)context.getApplicationContext();
    }   
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值