Android 内核--Context对象
Context(在Android中翻译为场景):一个Activity就是一个Context,一个Service也是一个Context,应用程序中有多少个Activity或者Service,就会有多少个Context对象; Android把"场景"抽象为Context类,用户和操作系统的每一次交互都是一个场景; 如打电话为有界面的场景,后台服务service为没界面的场景;
Context类本身是一个纯abstract类,为了使用方便,定义了ContextWrapper类,这只是一个包装而已,它的构造函数中必须包含一个真正的Context引用,同时它提供了attachBaseContext()用于给ContextWrapper对象中指定真正的Context对象,调用ContextWrapper的方法都会被转向其所包含的真正的Context对象。 ContextThemeWrapper类,内部包含了主题相关的接口,在此说的主题是指在Manifest.xml中通过android:theme为Application元素或者Activity元素指定的主题;
ContextImpl类真正实现了Context中所有函数,应用程序中调用的各种Context类的方法,其实现均来自于该类; 每一个应用程序都是从ActivityThread类开始的,创建Context对象也是在该类中完成,具体创建ContexImpl类的地方一共有7处;
- PackageInfo.makeApplication()
performLaunchActivity()
handleCreateBackupAgent()
handleCreateService()
handleBindApplication()
handleBindApplication()
attach()
attach()方法仅在Framework进程(system_server)启动时调用,应用程序运行时不会调用到该方法,需要明确的是system_server进程本身也是一个应用程序,所以其入口也是ActivityThread类,只是这个ActivityThread和一些系统服务运行在同一个进程空间中而已。
attach()方法中创建ContextImpl对象的基本逻辑如同以下三小点:
1、Application对应的Context
每个应用程序在第一次启动时,都会首先创建一个Application对象,默认的Application是应用程序的包名,用户可以重载默认的Application; 程序第一次启动时,会辗转调用到handleBindApplication()方法中,该方法中有两处创建了ContextImpl对象,但都是在if(data.instrumentationName!=null)条件中,该条件在一般的程序执行时都不会被执行到,只有当创建一个Android UnitTest工程时,相应的Test程序才能满足这个条件;
而如果不是测试工程的话,则调用makeApplication()方法
// If the app is being launched for full backup or restore, bring it up in
// a restricted environment with the base application class.
Application app = data.info.makeApplication(data.restrictedBackupMode, null);
下面是makeApplication函数处理方法代码
java.lang.ClassLoader cl = getClassLoader();
ContextImpl appContext = new ContextImpl();
appContext.init(this, null, mActivityThread);
app = mActivityThread.mInstrumentation.newApplication(cl, appClass, appContext);
appContext.setOuterContext(app);
即创建一个ContextImpl对象,然后调用init方法,其中第一个参数this指的是当前PackageInfo对象{LoadedApk.Java},该对象将赋值给ContextImpl类中的重要成员变量mPackageInfo。
需要注意的是PackageInfo对象从什么地方来的?就需要回溯到是谁调用了makeApplication()方法;
首先,AmS通过远程调用到ActivityThread的bindApplication()方法,该方法的参数包括两种,一种是ApplicationInfo,这是实现了Parcelable接口的数据类,意味着这个对象是由AmS创建的,通过IPC传递到ActivityThread中,另一种是其他的相关参数在bindApplication()方法中,
public final void bindApplication(String processName,
ApplicationInfo appInfo, List<ProviderInfo> providers,
ComponentName instrumentationName, String profileFile,
Bundle instrumentationArgs, IInstrumentationWatcher instrumentationWatcher,
int debugMode, boolean isRestrictedBackupMode, Configuration config,
Map<String, IBinder> services) {
//////
AppBindData data = new AppBindData();
//////
}
bindApplication方法创建一个本地AppBindData数据类,然后再去调用handleBindApplication。在调用handleBindApplication()的时候,AppBindData对象中的info变量还是空值,然后会使用data.info = getPackageInfoNoChecked方法为info变量赋值,
private final void handleBindApplication(AppBindData data) {
mBoundApplication = data;
/////
data.info = getPackageInfoNoCheck(data.appInfo);
/////
getPackageInfoNoCheck方法如下
public final LoadedApk getPackageInfoNoCheck(ApplicationInfo ai) {
return getPackageInfo(ai, null, false, true);
}
getPackageInfo方法如下:
private final LoadedApk getPackageInfo(ApplicationInfo aInfo,
ClassLoader baseLoader, boolean securityViolation, boolean includeCode) {
LoadedApk packageInfo = ref != null ? ref.get() : null;
if (packageInfo == null || (packageInfo.mResources != null
&& !packageInfo.mResources.getAssets().isUpToDate())) {
//...if (includeCode) {
mPackages.put(aInfo.packageName, new WeakReference<LoadedApk>(packageInfo));
} else {
mResourcePackages.put(aInfo.packageName, new WeakReference<LoadedApk>(packageInfo));
}
}
return packageInfo;
}
这个方法的内部实际上会根据AppBindData中的ApplicationInfo中的mPackageName创建一个PackageInfo对象,并把这个对象保存为ActivityThread类的全局对象,显然,一个应用程序中的所有Activity或者Application对象对应的mPackageName都一样,即为包的名称,所以ActivityThread中会产生一个全局PackageInfo对象。
接下来,回到data.info.makeApplication()方法,这是PackageInfo对象的来源;以上流程可以总结如下
2、Activity对象中获取Context对象
启动Activity时,AmS会通过IPC调用到ActivityThread的scheduleLaunchActivity方法,该方法包含一个参数ActivityInfo,这是一个实现了Parcelable接口的数据类,意味着该对象是AmS创建的,并通过IPC传递到ActivityThread;另一些参数如下。
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Bundle state, List<ResultInfo> pendingResults,
List<Intent> pendingNewIntents, boolean notResumed, boolean isForward) {
ActivityClientRecord r = new ActivityClientRecord();
......
}
scheduleLaunchActivity方法中会创建一个本地ActivityRecord数据类,ActivityThread内部会为每一个Activity创建一个ActivityRecord对象,并使用这些数据来管理Activity。
接下来会调用handleLaunchActivity(),然后再调用performLaunchActivity(),该方法中创建ContextImpl代码如下:
ContextImpl appContext = new ContextImpl();
appContext.init(r.packageInfo, r.token, this);
appContext.setOuterContext(activity);
ContextImpl.init方法中的第一个参数来源即为performLaunchActivity中
ActivityInfo aInfo = r.activityInfo;
if (r.packageInfo == null) {
r.packageInfo = getPackageInfo(aInfo.applicationInfo,
Context.CONTEXT_INCLUDE_CODE);
}
即在performLaunchActiviy开始执行时,首先为r.packageInfo赋值,getpackageInfo方法的执行逻辑和getPackageInfoNoChecked()基本相同,所以,r.packageInfo对象的PackageInfo对象和Application对应的packageInfo对象是同一个。
3、Service对应的Context
启动Service时,AmS首先会通过IPC调用到ActivityThread的scheduleCreateService()方法,该方法包含两个参数。第一种是ServiceInfo,这是实现了一个Parcelable接口的类,意味着该对象由Ams创建,并通过IPC传递到ActivityThread内部,第二种是其他参数。
public final void scheduleCreateService(IBinder token, ServiceInfo info) {
CreateServiceData s = new CreateServiceData(); // ......
s.token = token;
s.info = info;
queueOrSendMessage(H.CREATE_SERVICE, s);
}
在scheduleCreateService()方法中,会创建一个CreateServiceData的数据对象,ActivityThread会为其所包含的每一个Service创建该数据对象,并通过这些对象来管理Service。
接着,会执行handleCreateService()方法,其中创建ContextImpl对象的代码如下:
ContextImpl context = new ContextImpl();
context.init(packageInfo, null, this);
context.setOuterContext(agent);
agent.attach(context);
同样context.init()方法中packageInfo的赋值操作为handleCreateService方法中通过如下代码实现
LoadedApk packageInfo = getPackageInfoNoCheck(data.info.applicationInfo);
赋值代码同样使用了getPackageInfoNoCheck()方法,意味着Service对应的Context对象内部的mPackageInfo与Activity、Application中是完全相同的;
总结流程图如下:
4、Context之间的关系
从以上三节可以看出,创建Context对象的过程基本上是相同的,包括代码结构也很类似,不同的是针对Application、Activity、Service使用了不同的数据对象
不同Context子类中PackageInfo的来源如上表
一个应用程序中包含的Context个数为:Service个数 + Activity个数 + 1(Application类本身对应一个Context对象)
应用程序中包含多个ContextImpl对象,而其内部变量mPackageInfo指向同一个PackageInfo对象,这种设计意味着ContextImpl是一种轻量级,而PackageInfo是一个重量级;ContextImpl中的大多数进行包操作的重量级函数实际上都转向了mPackageInfo对象相应的方法,即事实上是调用了同一个PackageInfo对象;
Android 内核--Context对象的更多相关文章
- 转:Android中Context详解 ---- 你所不知道的Context
转:http://blog.csdn.net/qinjuning/article/details/7310620 转:http://blog.csdn.net/lmj623565791/article ...
- Android中Context具体解释 ---- 你所不知道的Context
...
- Android在Context详细解释 ---- 你不知道Context
...
- Android中Context详解 ---- 你所不知道的Context(转)
Android中Context详解 ---- 你所不知道的Context(转) 本文出处 :http://b ...
- Android中Context详解
大家好, 今天给大家介绍下我们在应用开发中最熟悉而陌生的朋友-----Context类 ,说它熟悉,是应为我们在开发中时刻的在与它打交道,例如:Service.BroadcastReceiver.A ...
- Android中Context详解 ---- 你所不知道的Context
转自:http://blog.csdn.net/qinjuning/article/details/7310620Android中Context详解 ---- 你所不知道的Context 大家好, ...
- Android RSA加密对象数据
前几天说了手头项目用MD5和双向加密DES来进行加密的,因为产品是在不断的改造中完善的.考虑到DES和MD5加解密还是会存下一定的风险,于是产品一拍,不行,听你们说MD5加密是不安全的,咱们产品以后做 ...
- android ApplicationContext Context Activity 内存的一些学习
Android中context可以作很多操作,但是最主要的功能是加载和访问资源. 在android中有两种context,一种是application context,一种是activity cont ...
- 《深入理解Android内核设计思想》
<深入理解Android内核设计思想> 基本信息 作者: 林学森 出版社:人民邮电出版社 ISBN:9787115348418 上架时间:2014-4-25 出版日期:2014 年5月 开 ...
随机推荐
- Spring Boot 2.x Redis多数据源配置(jedis,lettuce)
Spring Boot 2.x Redis多数据源配置(jedis,lettuce) 96 不敢预言的预言家 0.1 2018.11.13 14:22* 字数 65 阅读 727评论 0喜欢 2 多数 ...
- SpringBoot学习:整合shiro(rememberMe记住我后自动登录session失效解决办法)
项目下载地址:http://download.csdn.NET/detail/aqsunkai/9805821 定义一个拦截器,判断用户是通过记住我登录时,查询数据库后台自动登录,同时把用户放入ses ...
- 使用GC 初始化DG(将备份集复制到目标端再初始化)
概述 当前环境中有一个GC节点,一套RAC 11.2.0.4的数据库,一个已经使用GC进行在线初始化好的dg环境,需要模拟在远端使用rman备份集进行初始化DG的操作. 恢复环境 当前环境中 已经 ...
- 下载Web微信视频
1. 用浏览器(我用Chrome)登录web微信(wx.qq.com) 2. 这个时候如果有人发视频,可以点开播放.用F12打开chrome的调试平台,查看视频源的URL(绿色框的src内容) 3. ...
- 「日常训练」Regular Bridge(Codeforces Round 306 Div.2 D)
题意与分析 图论基础+思维题. 代码 #include <bits/stdc++.h> #define MP make_pair #define PB emplace_back #defi ...
- hdu2098分拆素数和(素数+暴力)
分拆素数和 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submi ...
- HTML <head>里面的标签
<head> 中的标签可以引用脚本.指示浏览器在哪里找到样式表.提供元信息等等. 下面这些标签可用在 head 部分:<base>, <link>, <met ...
- pycharm 3.4 亲测可使用到2019年2月的注册码,要用者从速
注册码: D87IQPUU3Q-eyJsaWNlbnNlSWQiOiJEODdJUVBVVTNRIiwibGljZW5zZWVOYW1lIjoiTnNzIEltIiwiYXNzaWduZWVOYW1l ...
- selenium,unittest——驾照科目一网上答题自动化
需求很简单,所有题目全选A,然后点提交出分,校验是否到达出分这步 遇到的坑有这几个,一个是assertIn哪个是校验哪个是文本要分清,还有code的编码统一到Unicode,最后就是xpath定位各个 ...
- Visual Studio Code 工具使用教程
软件下载这里就不用讲了,安装完之后: 1.切换中文: 选择扩展 搜索“Language”,在下列选项选择 Chinese (Simplified) Language Pack for Visual S ...