Context
一、context概念理解
google解释如下:
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声明的一些主要方法:从中我们可以看出它既能获取进程id、包信息和权限等进程层面的信息;也能访问如assets、cache、sp、resource和database甚至contentresolver等资源文件;还能启动activity、绑定service、注册receiver和发送broadcast等。
那么为什么要设计context呢?它的意义是什么呢?context的字面意思是“上下文”。谁的“上下文”呢?是进程的“上下文”,也是我们开发app应用的“上下文”。context声明了一个app最基本的权利。我们创建一个空项目,即使什么业务逻辑也不写,我们依然可以获取进程id,可以访问resource,也可以启动一个activity或者service,这就是app的基本权利;但是我们获取进程id干什么,resource里有什么资源,启动一个activity要展示怎样的界面,绑定一个service又想做哪些复杂的算法?这些都是我们基于基本权利之上的业务逻辑!当然,同时context也规定了app的边界,app无法向系统要求声明之外的过分要求,比如从应用层面,我们不能修改userid。简而言之,context可以理解为系统和app之间的一份权利声明!
二、context架构设计
context 是一个纯抽象类,规范了app和系统之间的交互。contextimpl真正实现context所有函数。contextwrapper则只是对context做了简单的封装,其内部所有继承函数的实现都是由contextimpl实例代理完成的。正因如此,所有contextwrapper实例被系统创建时都会通过attachbasecontext( )方法将一个contextimpl实例赋值给其全局变量mbase。
这样的分层设计在面向对象程序设计里非常普遍,从设计模式角度来讲,这是一个标准的代理模式!这样的设计可以让抽象层可以更加专注于问题领域的分析和设计,而不必纠缠于具体实现,职责清晰,扩展性强。
系统为app提供了三种主要的context组件:application,service,activity。contextthemewrapper主要包含了与主题相关的接口,只有activity才需要主题。拿到这三种组件中任意一个就可以实现几乎所有context声明的权利,在日常开发中我们几乎没有关注过mcontext实例具体是哪种类型。但是在某些特殊情况下,可能会因为context类型使用不当造成runtimeexception异常,后面会做详细解释。那么一个进程中到底有多少个context呢?一般我们只考虑application、service和activity这三种类型,因此:
$$context数量=activity数量+service数量+1$$
context数量是实例化的activity和service数量之和再加一个application,而不是有些人误认为的一个app只有一个“上下文”。另外一个需要注意的是,android中的context对象并不是像java中那样随意new出来的,而是由系统在需要时创建的,具体代码在activitythread类中。
三、context实战应用
我们已经知道context是app要求系统兑现权利的法宝,而且一个app进程中可能有很多这样的法宝,但是有些法宝却并非在所有场景中总能显灵。因为,出于code规范或安全因素等,系统限制了某些类型context履行某些功能。毕竟,权力是系统给的,它也有责任防止滥用而造成隐患!比如,如果想在service里启动一个activity,就会造成如下异常:
throw new androidruntimeexception( "calling startactivity() from outside of an activity " + " context requires the flag_activity_new_task flag." + " is this really what you want?");
因为启动service是不会创建任务栈的,那么从service中启动的activity就无栈可存。如果强行加上flag_activity_new_task新建一个栈,也不是标准的方式,不建议这样设计。
下图给出了不同类型context具体使用范围和限制:
- 总体上context的操作都是允许的
- 除activity外其他类型context不能直接startactivity( ),需要追加flag_activity_new_task
- broadcastreceiver中不允许绑定service,这是因为静态注册的receiver,系统返回的context类型是receiverrestrictedcontext,查看源码可以看到其中重写了bindservice( )方法并直接抛出receivercallnotallowedexception异常;动态注册的receiver返回的是注册时的context,另行讨论。
- broadcastreceiver中允许通过registerreceiver(null, filter)方法来获取粘性广播,但不允许注册常驻的receiver。否则,同样会收到receivercallnotallowedexception异常。
上一篇: 前秦厉王苻生最后下场有多凄惨?
推荐阅读
-
PHP stream_context_create()函数的使用示例,createfile函数
-
php上下文(Context)选项和参数
-
PHP使用empty检查函数返回结果时报Fatal error: Can't use function return value in write context的问题 - 心中的飞梦
-
Android编程获取全局Context的方法
-
浅谈Spring Context加载方式
-
Android 中Context的使用方法详解
-
解析web.xml中在Servlet中获取context-param和init-param内的参数
-
Android编程中context及全局变量实例详解
-
PHP使用stream_context_create()模拟POST/GET请求的方法
-
关于Spring启动时Context加载源码分析