欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Context

程序员文章站 2022-05-22 13:28:50
一、Context概念理解 Google解释如下: Interface to global information about an application environment. This is an abstract class whose implementation is provided ......

一、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

  上图列出了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。

  这样的分层设计在面向对象程序设计里非常普遍,从设计模式角度来讲,这是一个标准的代理模式!这样的设计可以让抽象层可以更加专注于问题领域的分析和设计,而不必纠缠于具体实现,职责清晰,扩展性强。

Context

  系统为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

  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异常。