博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Context
阅读量:4984 次
发布时间:2019-06-12

本文共 2830 字,大约阅读时间需要 9 分钟。

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

 

转载于:https://www.cnblogs.com/not2/p/10844910.html

你可能感兴趣的文章
SQlite数据库
查看>>
前端开发要注意的浏览器兼容性问题整理
查看>>
Python服务器开发 -- 网络基础
查看>>
开源项目Html Agility Pack实现快速解析Html
查看>>
一些常用的js,jquerry 样例
查看>>
Oracle PL/SQL 多重选择句
查看>>
dorado中的creationType选择类型
查看>>
C++11 数值类型和字符串的相互转换
查看>>
无锡盈达聚力科技有限公司
查看>>
tyvj1659中中救援队
查看>>
kubernetes学习:CKA考试题
查看>>
LINUX samba的安装使用
查看>>
CSS border 生成三角
查看>>
asp.net(c#)开发中的文件上传组件uploadify的使用方法(带进度条)
查看>>
7.STM32中GPIO理解
查看>>
base64 json
查看>>
在vim中搜索单词
查看>>
设置定点数学属性
查看>>
自动化测试工具 Test Studio入门教程
查看>>
Python之进程线程
查看>>