当前位置: 首页 > news >正文

Android Context 到底是什么?

什么是Android Context?

一个Context意味着一个场景,一个场景就是我们和软件进行交互的一个过程。比如和妹纸约会的月下小桥,比如当你使用微信的时候,场景包括聊天界面、通讯录、朋友圈,以及背后的一些数据。

那么从安卓程序的角度来看,Context是什么?其实一个Activity就是一个Context,一个Service也是一个Context。

一个应用程序可以认为是一个约会环境,用户在这个环境中会切换到不同的场景,比如先去有情调的饭店吃饭,再去电影院看个电影,然后再去xxx(此处省略一万字...)。

Activity类的确是基于Context,而Service类也是基于Context。Activity除了基于Context类外,还实现了一些其他重要的接口,从架构设计的角度看,interface仅仅是某些功能,而extends才是类的本质,即Activity的本质是一个Context,其所实现的其他接口只是为了扩充Context的功能而已,扩充后的类称之为一个Activity或Service。

一个应用程序中应该有多少个Context对象

我们在应用程序开发中经常会调用Context的一些方法,这些方法看起来似乎会返回一些全局的对象,而不仅仅是某个Activity,可能会有点疑问,一个应用程序到底有多少个Context对象呢?比如,Context.getResources()返回该应用程序所对应的Resource类对象,无论从哪个Activity中调用,都会返回同一个Resource对象。

  • 一个Activity就是一个场景(Context),一个Service也是一个场景,所以,应用程序中有多少个Activity或者Service就会有多少个Context对象,也就是有多少个场景。
  • getResource()等方法返回的是同一个全局对象。

Context 继承关系是怎么样的呢?

Context类及其子类的继承关系

Context类本身是一个纯abstract类。为了使用方便又定义了Context包装类-ContextWrapper,穿上了一身装备显得也比较强大,ContextWrapper构造函数中必须包含一个真正的Context引用,同时ContextWrapper中有attachBaseContext()用于给ContextWrapper对象中指定真正的Context对象。

ContextThemeWrapper内部包含了与主题相关的接口,这里的主题就是指在AndroidManifest.xml中通过android:theme为Application或者Activity指定的主题。

只有Activity才需要主题,Service默默的后台工作者不需要穿的那么鲜艳,所以Service直接继承于ContextWrapper。

ContextImpl类真正实现了Context中所有的函数,真正的八块腹肌,我们所调用的各种Context类的方法其实实现均来自于该类。

什么时候创建的Context?

每一个应用程序在客户端都是从ActivityThread类开始的,创建Context对象也是在该类中完成,具体创建ContextImpl类的地方一共有6处:

  • PackageInfo.makeApplication()
  • performLaunchActivity()
  • handleCreateBackupAgent()
  • handleCreateService()
  • handleBindApplication()
  • attach()

其中attach()方法仅在Framework进程启动时调用,应用程序运行时不会调用到该方法。

Application对应的Context

程序第一次启动时,会辗转调用到makeApplication()方法。具体代码如下:

ContextImpl appContext = new ContextImpl();
appContext.init(this,null,mActivityThread);
....
appContext.setOuterContext(app);复制代码

Activity对应的Context

启动Activity时,Ams会通过IPC调用到ActivityThread的scheduleLaunchActivity()方法,该方法包含两种参数。一种是ActivityInfo,这是一个实现了Parcelable接口的数据类,意味着该对象是Ams创建的,并通过IPC传递到ActivityThread;另一种是其他的一些参数。

scheduleLaunchActivity()方法中会根据以上两种参数构造一个本地ActivityRecord数据类,ActivityThread内部会为每一个Activity创建一个ActivityRecord对象,并使用这些数据对象来管理Activity。

然后会调用handleLaunchActivity(),再调用performLaunchActivity(),该方法中创建ContextImpl的代码如下:

ContextImpl appContext = new ContextImpl();
appContext.init(r.packageInfo,r.token,this);
appContext.setOuterContext(activity);复制代码

在performLaunchActivity()开始执行时,会为r.packageInfo变量赋值。r.packageInfo对象的PackageInfo对象和Application对应的packageInfo对象是同一个。

Service对应的Context

启动Service时,Ams会通过IPC调用到ActivityThread的scheduleCreateService()方法,该方法也包含两种参数。第一种是ServiceInfo,这是实现了一个Parcelable接口的数据类,该对象由AmS创建,并通过IPC传递到ActivityThread内部;第二种是其他参数。

在scheduleCreateService()方法中,会使用以上两种参数构造一个CreateServiceData的数据对象,ActivityThread会为其所包含的每一个Service创建该数据对象,并通过这些对象来管理Service。

然后在执行handleCreateService()方法,创建ContextImpl对象代码如下:

ContextImpl appContext = new ContextImpl();
appContext.init(packageInfo,null,this);
...
appContext.setOuterContext(service);复制代码

Service对应的Context对象内部的mPackageInfo与Activity、Application中是完全相同的。

这几个Context之间的关系

从以上可以看出,创建Context对象的过程基本上是相同的,不同的仅仅是针对Application、Activity、Service使用了不同的数据对象。

一个应用程序包含的Context个数应该为:Context个数 = Service个数+Activity个数+1,最后的1是Application类本身也会对应一个Context对象。

应用程序中包含多个ContextImpl对象,而内部变量mPackageInfo却指向同一个PackageInfo对象,这种设计结构一般意味着ContextImpl是一种轻量级类,而PackageInfo是一个重量级类。事实上确实是这样,ContextImpl中的大多数进行包操作的重量级函数实际上都是转向了mPackageInfo对象相应的方法,也就是事实上调用了同一个PackageInfo对象。

如有问题请留言,转载请注明出处

备注:以上部分思想来自于《Android内核剖析》

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • react-native 基础:react-native-router-flux 的使用[意译]
  • 【Scrapy】 Feed exports 学习记录四
  • 使用jquery.PrintArea.js打印网页的样式问题
  • 2013年回顾,关于敏捷实践,关于j2ee等等
  • 解决 Springboot Unable to build Hibernate SessionFactory @Column命名不起作用
  • 读书笔记 --TCP :传输控制协议(一)
  • spring data mongo groupby实例
  • 缓冲器的学习
  • 理解 Linux shell 中的一个方言:21
  • HBase 数据读写流程
  • Jquery中$.get(),$.post(),$.ajax(),$.getJSON()的用法总结
  • powershell: 生成随机字符串
  • 使用httpClient上传至远程服务器
  • Kafka Offset Storage
  • jvm理论-运行时数据区
  • hexo+github搭建个人博客
  • 10个确保微服务与容器安全的最佳实践
  • ERLANG 网工修炼笔记 ---- UDP
  • ES6核心特性
  • EventListener原理
  • Hibernate最全面试题
  • Next.js之基础概念(二)
  • passportjs 源码分析
  • Python十分钟制作属于你自己的个性logo
  • WinRAR存在严重的安全漏洞影响5亿用户
  • 等保2.0 | 几维安全发布等保检测、等保加固专版 加速企业等保合规
  • 关于springcloud Gateway中的限流
  • 用简单代码看卷积组块发展
  • 转载:[译] 内容加速黑科技趣谈
  • ​​快速排序(四)——挖坑法,前后指针法与非递归
  • ​3ds Max插件CG MAGIC图形板块为您提升线条效率!
  • ​一帧图像的Android之旅 :应用的首个绘制请求
  • ​字​节​一​面​
  • # windows 运行框输入mrt提示错误:Windows 找不到文件‘mrt‘。请确定文件名是否正确后,再试一次
  • #微信小程序(布局、渲染层基础知识)
  • $nextTick的使用场景介绍
  • (12)Hive调优——count distinct去重优化
  • (145)光线追踪距离场柔和阴影
  • (8)Linux使用C语言读取proc/stat等cpu使用数据
  • (Java企业 / 公司项目)点赞业务系统设计-批量查询点赞状态(二)
  • (附源码)python旅游推荐系统 毕业设计 250623
  • (附源码)ssm考生评分系统 毕业设计 071114
  • (六)Hibernate的二级缓存
  • (贪心 + 双指针) LeetCode 455. 分发饼干
  • (图)IntelliTrace Tools 跟踪云端程序
  • (一)Kafka 安全之使用 SASL 进行身份验证 —— JAAS 配置、SASL 配置
  • (一)基于IDEA的JAVA基础12
  • (一)项目实践-利用Appdesigner制作目标跟踪仿真软件
  • (原創) 人會胖會瘦,都是自我要求的結果 (日記)
  • (转)关于如何学好游戏3D引擎编程的一些经验
  • (转载)跟我一起学习VIM - The Life Changing Editor
  • .form文件_一篇文章学会文件上传
  • .NET COER+CONSUL微服务项目在CENTOS环境下的部署实践
  • .net core 管理用户机密
  • .NET Core 通过 Ef Core 操作 Mysql