当前位置: 移动技术网 > 移动技术>移动开发>Android > Context

Context

2019年05月11日  | 移动技术网移动技术  | 我要评论

一、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具体使用范围和限制:

 √代表允许,×代表不允许,?代表分情况

  1. 总体上context的操作都是允许的
  2. 除activity外其他类型context不能直接startactivity( ),需要追加flag_activity_new_task
  3. broadcastreceiver中不允许绑定service,这是因为静态注册的receiver,系统返回的context类型是receiverrestrictedcontext,查看源码可以看到其中重写了bindservice( )方法并直接抛出receivercallnotallowedexception异常;动态注册的receiver返回的是注册时的context,另行讨论。
  4. broadcastreceiver中允许通过registerreceiver(null, filter)方法来获取粘性广播,但不允许注册常驻的receiver。否则,同样会收到receivercallnotallowedexception异常。

 

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网