Android Context 到底是什么?

什么是Context?

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

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

一个应用程序可以认为是一个工作环境,用户在这个工作环境中会切换到不同的场景,这就像一个助理,他可能需要接待客人,可能还要打印文件,还可能接听电话,而这些就称之为不同的场景,助理可称之为一个应用程序。

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对象。

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

本页内容版权归属为原作者,如有侵犯您的权益,请通知我们删除。
美颜包含磨皮、美白、瘦脸等效果,其中磨皮算法在很多博客中均有介绍 例如: 双指数边缘平滑滤波器用于磨皮算法的尝试 选择性模糊及其算法的实现 基于局部均方差相关信息的图像去噪及其在实时磨皮美容算法中的应用 导向滤波磨皮 递归双边滤波磨皮 以上博客均有相关代码/公式,经试验若选取合适参数均有不错的效果,可惜水平有限尚未在shader中实现不卡顿的实时效果~ 观察美图秀秀和华为自带相机等相机APP,发现实时美颜效果均不如PC端和手机端后处理,可能在这一领域目前解决办法不多或者需求不高吧。 下面就探讨简单的美颜滤

闪屏(Splash) - 2015-12-17 19:12:52

好久没弄ReactNative了, 写个如何实现闪屏(Splash)的文章吧. 注意: (1) 如何切换页面. (2) 如何使用计时器TimerMixin. (3) 如何使用动画效果. (4) 如何加载Android的项目资源(图片). 1. 准备 新建项目, 添加主模块 index.android.js . /* @flow */ /** * 测试 * @author wangchenlong */ 'use strict' ; var React = require ( 'react-native'
1. Local storage背景     cookie弊端:同域内http请求都会带cookie,增加带宽和流量;有个数和大小限制(约4K)。     在HTML5中,本地存储是一个window的属性,包括localStorage和sessionStorage,从名字应该可以很清楚的辨认二者的区别,前者是一直存在本地的,后者只是伴随着session,窗口一旦关闭就没了。二者用法完全相同。
MSM8909+Android5.1.1通过USB连接XP系统无法识别问题   遇到此问题,可以安装应用宝、腾讯手机管家等手机管理软件,应该可正常让Android设备和XP系统正常通信。喜欢折腾的朋友可以看下面的实践总结。   USB连接方式: 图1   1.     媒体设备(MTP) 图2 自动安装软件提示安装失败,参考解决此问题 http://www.apk3.com/androidnews/html/1577.html (1)  安装XP完整新版的Windows Media Player 11 此
苹果官方有一句话说的非常好: 当控制器的view互为父子关系,那么控制器最好也互为父子关系 我之前有一篇博客说 控制器view的显示 里边我说了一个很严重的问题,就是当控制的view还在,但是控制器不在了,造成了数据无法显示的问题,所以我们就要想办法保住控制器的命。那么我们今天继续来看一下,如何保住控制器的命。 今天我们来用屏幕旋转的一个案例来说明一个问题:当控制器的view互为父子关系的时候,控制器不是父子关系时,会出现什么严重的问题。 看一个案例,在ipad开发中,屏幕旋转是经常要发生的事情,因为屏幕

[置顶] App性能优化浅谈 - 2015-12-17 18:12:51

前言 前段时间给公司的小伙伴们进行了关于app性能优化的技术分享,这里我稍微整理一下也给大家分享一下,关于性能优化这个话题很大,涉及面可以很广,也可以很深入,本人能力有限,不会给大家讲特别难懂,特别底层的东西,都是我们开发能着手去做的点,大家都在讲性能优化,但对于项目经验不够丰富的朋友很难有一个概念,做优化的时候也会比较茫然,这里我就给大家指明方向。 从何讲起? 笔者在做产品开发的时候,也遇到性能瓶颈,测试工程师反馈了一些比较明显的问题,比如UI界面的过度绘制,列表滑动有明显卡顿,比较耗内存等等,但以往的
MSM8909+Android5.1.1的USB连接方式介绍   默认是采用WIN7电脑测试的。   1.     MTK6582+Android4.4 USB连接方式 图1   (1)  USB存储设备 XP系统推荐,将手机作为U盘进行文件复制。 图2 打开USB存储设备,电脑端显示为可移动磁盘,进入显示如下: 图3   (2)  媒体设备(MTP) 让您可以在Windows上传输媒体文件,或在Mac上使用Android文件传输应用来传输文件。 图4 选择“打开设备以查看文件”,进去之后看到的内容和图3
iOS HLS 流媒体文件打散问题 - 只有声音无影像 太阳火神的美丽人生 ( http://blog.csdn.net/opengl_es ) 本文遵循“ 署名-非商业用途-保持一致 ”创作公用协议 转载请保留此句: 太阳火神的美丽人生 -  本博客专注于  敏捷开发及移动和物联设备研究:iOS、Android、Html5、Arduino、pcDuino , 否则,出自本博客的文章拒绝转载或再转载,谢谢合作。 HTTP Live Streaming (HLS) 上面是官方的专栏页,在 其中下载 相应的工
读取文件和文件夹名 这一节开始我们将陆续看到UWP通用应用是如何获取到文件及文件夹的属性等信息,以及如何写入和读取数据等,当然了最重要的还是如何保存读取和删除应用的数据。 在Windows上读取文件名、文件夹名 首先我们在XAML中定义一个Button和TextBlock,将读取文件/文件夹名的过程写在前者的click事件中,后者则用来显示文件信息。 Grid Background = "{ThemeResource ApplicationPageBackgroundThemeBrush}" StackP
市场人员反映公司的app使用系统设置俄语、西班牙语,double数据会把小数点变为逗号。调试一下,是自定义的语言时候(例如,俄语、西班牙语)转换String.format("%.2f",67.876)。会出现的。 1、android 系统,设置系统语言的步骤 Android【设置】-【语言和输入法】-【语言】列表中找到相应语言所对应的列表项 2、问题分析 java.util.Locale类 在这个Locale类里面,有些语言是没有,例如俄语、西班牙语等。那么这时候android开发时候需要这些语言,怎么办