Context源码分析
我们做安卓开发,时时都在和Context打交道,那么Context到底是什么?有什么作用?如何与Application,Activity,Service等实例发生联系的?等等
Context是什么?
Context的字面意思是“上下文”,那么这个“上下文”到底指的是什么?“上”指的是什么?“下”指定的是什么?
个人的理解,有助于自己的理解的方式,不一定对,如果有更好的看法可以一块交流学习。个人的理解,“上”指的是在APP启动的时候,就与Context有关了,这个时候还是系统启动阶段,就与Context发生了联系。
“下”指定的是在APP界面正常显示出来以后,正常与用户交互的过程中,可以用Context获取资源,系统服务等。所以Context所谓的上下文就是承上启下的作用。
Context的类的继承关系
从上图可以看到,Context只有一个实现类ContextImpl,Application,Service,Activity都是直接或者间接继承了ContextWrapper,ContextWrapper中有一个变量mBase,也是个Context类型,实际是ContextImpl的对象,Application,Service,Activity所有的操作都是委托给了mBase实现。Context既然是承上启下,是个上下文,和APP启动流程有关,先来看看系统的启动流程和APP的启动流程,都在一张图里,如下:
从上图可以看到:
- 首先系统的第一个进程 init跑起来,作一些初始化相关的工作,然后通过系统调用fork出了一个zygote进程,init进程通过poll阻塞在那了。
- zygote进程被init进程fork出来以后,做一些jni初始化等,通过调用fork出了一个SystemServer进程,SystemServer进程里面跑的都是安卓的系统服务,zygote通过jni调用java的代码,fork出了SystemServer进程,打开了java世界的大门,自己通过sokcet监听阻塞在那了,监听来自socket的信息。
- SystemServer进程被fork出来以后,里面会开启非常多的系统服务,比如AMS,PMS,WMS等,SystemServer进程是一个非常重要的进程,系统的很多重要的服务都驻留在此进程中,SystemServer进程是通过Handler机制阻塞在那了。等待发来的消息并处理消息。这样整个系统就启动了。
- 在PMS中,会启动Lanuher APP,用户就可以看到安卓系统桌面了。如果用户点击了桌面上的QQ图标,Lannuher进程就会通过binder机制与AMS通信,告诉AMS要启动QQ应用,AMS收到 Lanuher进程发来的消息以后,通过socket发送信息给zygote进程,我们知道zygote进程在fork出了SystemServer进程以后就一直在监听着socket,所以zygote进程收到SystemServer进程发来的消息后,如果没有创建过QQ进程,这个时候,zygote就会调用fork系统调用创建一个新的进程,用来跑QQ代码,这个进程就是QQ进程,QQ App进程创建以后第一个调用的就是Activity.main()方法,如上图。
Context有什么作用?
1 访问当前应用的资源
- getResources
- getAssets
2 启动其它组件
- Activity
- Service
3 获取系统服务
- getSystemService
Application对象的ContextImpl对象创建过程
1 通过上面的系统启动流程和APP启动流程分析可知:第一个APP应用都是由AMS通过binder机制创建一个新的进程,然后调用ActivityThread类中的main方法开始的。很多人可能会感到奇怪为啥Android也是基于Java实现的,为啥没有看到main方法呢?其实整个App应用的入口就是ActivityThread.main方法.所有有关Application, Activity,Service的创建都是在ActivityThread类中,其实该类就是我们App的主线程。在ActivityThread中有一个方法 performLaunchActivity()方法,在这个方法里面就创建了Application,Activity。我们看一下这个方法。
如下图
调用mInstrumentation.newActivity()方法创建Activity。newActivity代码如下图
可以看到,创建Activity以后,调用了Activity的attach方法,第一个参数就是context,在这里Activity就和context发生了联系,这个context其实就是ContextImpl的实例。接着上面的第一张图 performLaunchActivity继续往下走,如下图:
通过上图可以看到,在创建完了activity,并且调用了activity.attach()方法之后,开始创建Application对象,如下
Application app = r.packageInfo.makeApplication(false,mInstrumentation)
makeApplication代码如下:
随后又创建了一个ContextImpl的实例,代码如下
//创建ContextImpl实例
ContextImpl appContext = new ContextImpl();
//初始化ContextImpl实例
appContext.init(this,null,mActivityThread);
//把appContext传给了newApplication方法
app = mActivityThread.mInstrumentation.newApplication(cl,appClass,appContext);
//与Application发生联系,ContextImpl实例保存了Application的实例app
appContext.setOuterContext(app);
mActivityThread.mAllApplication.add(app);
mApplication = app;
下面看下newApplicaiton()方法,代码如下:
static public Application newApplication(Class<?> clazz,Context context){
//通过反射创建Application实例
Application app = (Application)clazz.newInstance();
//把上面传进来的ContextImpl实例通过attach方法保存了起来
app.attach(context);
//返回Application实例
return app;
}
创建完Application并且通过调用application实例的attach方法与ContextImpl实例发生了联系,接下来就应该调用application的onCreate()方法了。代码如下:
public void callApplicationOnCreate(Application app){
//调用Application的onCreate方法
app.onCreate();
}
创建了activity,也创建了application并且调用了application的attach和onCreate方法,接下来应该调用activity的onCreate方法了。还是在performLanucherActivity方法中。如下图:
如上图,通过mInstructation的callActivityOnCreate()方法调用activity的onCreate()。这段代码和调用application的onCreate()方法的逻辑类似,自己可以看一下。这里不再帖出代码
*** 通过上面的分析可以知道,Context是什么时候创建的,是怎么创建的,何时初始化的,如何与Application和Activity发生联系的等 ***
Application的生命周期为什么这么长?
我们知道,Application的生命周期是和APP进程一样长的,Application对应的context也是一样,为什么Application的生命周期为什么这么长?
通过上面的分析可以知道,APP进程的入口是ActivityThread.main()方法,在这个方法中创建了一个ActivityThread的实例,通过Handler阻塞在那。ActivityThread的实例就会一直存在,如果APP不退出的话,而ActivityThread的实例中保存了application的mAllApplications,这是一个数组,保存Application实例的,在创建Application实例的时候,通过mActivityThread.mAllApplications.add(app),把app保存起来了,通过强引用可以知道,ActivityThread引用了application实例,而ActivityThread实例又在进程的循环中,一直在阻塞,所以Application的生命周期和进程一样。
Context的用法注意
下面以一张图来说明几种Context的不同点和用法。
Context源码分析的更多相关文章
- go context 源码分析
WithCancel func WithCancel(parent Context) (ctx Context, cancel CancelFunc) { c := newCancelCtx(pare ...
- Android源码分析-全面理解Context
前言 Context在android中的作用不言而喻,当我们访问当前应用的资源,启动一个新的activity的时候都需要提供Context,而这个Context到底是什么呢,这个问题好像很好回答又好像 ...
- requirejs源码分析: requirejs 方法–2. context.require(deps, callback, errback);
上一篇 requirejs源码分析: requirejs 方法–1. 主入口 中的return context.require(deps, callback, errback); 调用的是make ...
- ABP源码分析二十四:Notification
NotificationDefinition: 用于封装Notification Definnition 的信息.注意和Notification 的区别,如果把Notification看成是具体的消息 ...
- asp.net mvc 之旅 —— 第六站 ActionFilter的应用及源码分析
这篇文章我们开始看一下ActionFilter,从名字上其实就大概知道ActionFilter就是Action上的Filter,对吧,那么Action上的Filter大概有几个呢??? 这个问题其实还 ...
- 深入理解 spring 容器,源码分析加载过程
Spring框架提供了构建Web应用程序的全功能MVC模块,叫Spring MVC,通过Spring Core+Spring MVC即可搭建一套稳定的Java Web项目.本文通过Spring MVC ...
- jQuery 2.0.3 源码分析 Deferred(最细的实现剖析,带图)
Deferred的概念请看第一篇 http://www.cnblogs.com/aaronjs/p/3348569.html ******************构建Deferred对象时候的流程图* ...
- jQuery 2.0.3 源码分析 Deferred概念
JavaScript编程几乎总是伴随着异步操作,传统的异步操作会在操作完成之后,使用回调函数传回结果,而回调函数中则包含了后续的工作.这也是造成异步编程困难的主要原因:我们一直习惯于“线性”地编写代码 ...
- jQuery-1.9.1源码分析系列(一)整体架构续
这一节主要是jQuery中最基础的几个东东 2. jQuery的几个基础属性和函数 a. jQuery.noConflict函数详解 在jQuery初始化的时候保存了外部的$和jQuery _j ...
随机推荐
- Android开源项目库汇总
最近做了一个Android开源项目库汇总,里面集合了OpenDigg 上的优质的Android开源项目库,方便移动开发人员便捷的找到自己需要的项目工具等,感兴趣的可以到GitHub上给个star. 抽 ...
- 整合最优雅SSM框架:SpringMVC + Spring + MyBatis
我们看招聘信息的时候,经常会看到这一点,需要具备SSH框架的技能:而且在大部分教学课堂中,也会把SSH作为最核心的教学内容. 但是,我们在实际应用中发现,SpringMVC可以完全替代Struts,配 ...
- iOS 使用 UIMenuController 且不隐藏键盘的方法
iOS 使用 UIMenuController 且不隐藏键盘的方法 在键盘显示的时候使用 UIMenuController 弹出菜单,保持键盘显示且可输入的状态. 实现方法有 修改响应链(推荐) 遵循 ...
- C++ 元编程 —— 让编译器帮你写程序
目录 1 C++ 中的元编程 1.1 什么是元编程 1.2 元编程在 C++ 中的位置 1.3 C++ 元编程的历史 2 元编程的语言支持 2.1 C++ 中的模板类型 2.2 C++ 中的模板参数 ...
- 关于Java FTP SFTP的相关实际问题
第一个: java ftp使用的是Apache common-net,但是FTP服务侧提供的FTP服务器只支持SFTP,结果报 java.net.ConnectException: Connectio ...
- Python变量运算字符串等
一,作用域 操作 name = 'liuyueming' if 1==1:... print name... liuyueming 两次回车执行 修改代码 >>> if 1==1:. ...
- poj1125 Stockbroker Grapevine Floyd
题目链接:http://poj.org/problem?id=1125 主要是读懂题意 然后就很简单了 floyd算法的应用 代码: #include<iostream> #include ...
- Linux文件查看与查找命令
cat 查看一个文件 -E: 显示行结束符$ -n: 对显示出的每一行进行编号 -A:显示所有控制符 -b:非空行编号 -s:压缩连续的空行成一行 -T:显示制表符 常用:cat -An /etc/ ...
- Redis学习-复制
Redis支持简单且易用的主从复制(master-slave replication)功能, 该功能可以让从服务器(slave server)成为主服务器(master server)的精确复制品.以 ...
- ANSJ中文分词使用方法
一.前言 之前做solr索引的时候就使用了ANSJ进行中文分词,用着挺好,然而当时没有写博客记录的习惯.最近又尝试了好几种JAVA下的中文分词库,个人感觉还是ANSJ好用,在这里简单总结之. 二.什么 ...