关于ContextImp的源码分析

来源: http://blog.csdn.net/qinjuning/article/details/7310620

Context概述:

 

Android 开发文档对 Context描述:

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

大致意思如下:

1、它描述的是一个应用程序环境的信息,即上下文。

2、该类是一个抽象(abstract class)类,Android提供了该抽象类的具体实现类, 后面我们会讲到是ContextIml类

3、通过它我们可以获取应用程序的资源和类,也包括一些应用级别操作,例如:启动一个Activity,发送广播,接受Inten 信息等。

我们都知道Activity, Service, Application 类都是都是Context的子类, 类关系图如下:

1. ComtextImp是对抽象类Context 具体实现; ContextImp 有个成员 mOuterContext 类指向所属的ContextWrapper对象

2. ContextWrapper,对Context进行简易的包装(Wrapper),他有一个成员mBase, 这个mBase真正只想的是ContextImp 对象。 通过ContextImp的对象来实现从Context继承来的接口, 这种方式我们成为包装Wrapper. 这个类新增一个接口attachBaseContext, 使用这个方法简历mBase 和ContextImp对象的关系。

3. ContextThemeWrapper 在ContextWrapper基础上增加了Theme方面的接口, 对于Theme接口只有Activity会使用到。 所以Activity继承这个类

4. Service, Application 继承Service类

5、通过对ContextImp的分析可知,其方法的大多数操作都是直接调用其属性mPackageInfo(该属性类型为LoadedApk)的相关方法而来。ContextImp是一种轻量级类,而PackageInfo才是真正重量级的类。而一个App里的所有ContextIml实例,都对应同一个packageInfo对象。

说了这么多,我们还是用源码分析的方式,来阐述我们结论,我们按照以下三个情景对ContextWrapper的子类进行分析。

1.Apliation 对象 和 ContextImp对象的关系建立

2.Service   对象 和 ContextImp对象的关系建立

3.Activity  对象 和 ContextImp对象的关系建立

源码分析:

Context类: /frameworks/base/core/Java/android/content/Context.java

说明:  抽象类,提供了一组通用的API。

public abstract classContext{
...
public abstract Object getSystemService(String name);//获得系统级服务
public abstract void startActivity(Intent intent);//通过一个Intent启动Activity
public abstract ComponentName startService(Intent service);//启动Service
//根据文件名得到SharedPreferences对象
public abstract SharedPreferences getSharedPreferences(String name,int mode);
...
}

ContextIml.java: /frameworks/base/core/java/android/app/ContextImpl.java

说明:该Context类的实现类为ContextIml,该类实现了Context类的功能。请注意,该函数的大部分功能都是直接调用其属性mPackageInfo去完成,这点我们后面会讲到。

/**
* Common implementation of Context API, which provides the base
* context object for Activity and other application components.
*/
classContextImpl extends Context{
//所有Application程序公用一个mPackageInfo对象
/*package*/ActivityThread.PackageInfo mPackageInfo;
@Override
publicObject getSystemService(String name){
...
elseif(ACTIVITY_SERVICE.equals(name)){
return getActivityManager();
}
elseif(INPUT_METHOD_SERVICE.equals(name)){
returnInputMethodManager.getInstance(this);
}
}
@Override
publicvoid startActivity(Intent intent){
...
//开始启动一个Activity
mMainThread.getInstrumentation().execStartActivity(
getOuterContext(), mMainThread.getApplicationThread(), null, null, intent,-1);
}
}

ContextWrapper类 路径 \frameworks\base\core\java\android\content\ContextWrapper.java

说明: 正如其名称一样,该类只是对Context类的一种包装,该类的构造函数包含了一个真正的Context引用,即ContextIml对象。源代码(部分)如下:

publicclassContextWrapper extends Context{
Context mBase;//该属性指向一个ContextIml实例,一般在创建Application、Service、Activity时赋值
//创建Application、Service、Activity,会调用该方法给mBase属性赋值
protectedvoid attachBaseContext(Context base){
if(mBase != null){
thrownewIllegalStateException("Base context already set");
}
mBase = base;
}
@Override
publicvoid startActivity(Intent intent){
mBase.startActivity(intent);//调用mBase实例方法
}
}

ContextThemeWrapper类 路径:/frameworks/base/core/java/android/view/ContextThemeWrapper.java

说明:该类内部包含了主题(Theme)相关的接口,即android:theme属性指定的。只有Activity需要主题,Service不需要主题,所以Service直接继承于ContextWrapper类。源代码(部分)如下:

public classContextThemeWrapper extends ContextWrapper{
//该属性指向一个ContextIml实例,一般在创建Application、Service、Activity时赋值
privateContext mBase;
//mBase赋值方式同样有一下两种
publicContextThemeWrapper(Context base,int themeres){
super(base);
mBase = base;
mThemeResource = themeres;
}
@Override
protectedvoid attachBaseContext(Context newBase){
super.attachBaseContext(newBase);
mBase = newBase;
}
}

Activity类 、Service类 、Application类本质上都是Context子类, 更多信息大家可以自行参考源代码进行理解。

 

情景分析一:Apliation对象和ContextImp对象的关系建立

每个应用程序在第一次启动时,都会首先创建Application对象。如果对应用程序启动一个Activity(startActivity)流程比较清楚的话,创建Application的时机在创建handleBindApplication()方法中,该函数位于 ActivityThread.java类

//创建Application时同时创建的ContextIml实例
private final void handleBindApplication(AppBindData data){
...
///创建Application对象
Application app = data.info.makeApplication(data.restrictedBackupMode, null);
...
}
publicApplication makeApplication(boolean forceDefaultAppClass,Instrumentation instrumentation){
...
try{
java.lang.ClassLoader cl = getClassLoader();
ContextImpl appContext =newContextImpl();//创建一个ContextImpl对象实例
appContext.init(this, null, mActivityThread);//初始化该ContextIml实例的相关属性
///新建一个Application对象
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
appContext.setOuterContext(app);//将该Application实例传递给该ContextImpl实例
}
...
}

我们分析创建一个handleBindApplication中核心调用一个函数makeApplication , 在makeApplication中

1. 新建一个ContexImp 的对象,然后对这个类进行初始化

2. 调用Instrumentation.makeApplication 这个方法新建一个应用Appliation 对象app。

3. 调用函数ContexImp.setOuterContext 设置进程上下文的所属对象。

我们进入Instrumentation.makeApplication

publicApplication newApplication(ClassLoader cl,String className,Context context)
throws InstantiationException,IllegalAccessException,
ClassNotFoundException{
return newApplication(cl.loadClass(className), context);
}
/**
* Perform instantiation of the process's {@link Application} object. The
* default implementation provides the normal system behavior.
*
* @param clazz The class used to create an Application object from.
* @param context The context to initialize the application with
*
* @return The newly instantiated Application object.
*/
staticpublicApplication newApplication(Class<?> clazz,Context context)
throws InstantiationException,IllegalAccessException,
ClassNotFoundException{
Application app =(Application)clazz.newInstance();
app.attach(context);
return app;
}
 
1.在函数newApplication 方法中通过反射调用Appliation类的构造函数。
2.调用Application.attach简历 ContextImp 和 Appliation 对象的关系, 实现如下,
 
public class Application extends ContextWrapper implements ComponentCallbacks {
/* package */ final void attach(Context context){
attachBaseContext(context);
}
}

情景分析二: Activity对象和ContextImp对象的关系建立

通过startActivity()或startActivityForResult()请求启动一个Activity时,如果系统检测需要新建一个Activity对象时,就会 回调handleLaunchActivity()方法,该方法继而调用performLaunchActivity()方法,去创建一个Activity实例

public final classActivityThread{
....
//创建一个Activity实例时同时创建ContextIml实例
private final void handleLaunchActivity(ActivityRecord r,Intent customIntent){
...
Activity a = performLaunchActivity(r, customIntent);//启动一个Activity
}
private final Activity performLaunchActivity(ActivityRecord r,Intent customIntent){
...
Activity activity = null;
try{
//创建一个Activity对象实例
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
}
if(activity != null){
ContextImpl appContext =newContextImpl();//创建一个Activity实例
appContext.init(r.packageInfo, r.token,this);//初始化该ContextIml实例的相关属性
appContext.setOuterContext(activity);//将该Activity信息传递给该ContextImpl实例
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
Configuration config =newConfiguration(mConfiguration);
if(DEBUG_CONFIGURATION)
Slog.v(TAG,"Launching activity "+ r.activityInfo.name +" with config "+ config);
activity.attach(appContext,this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstance,
r.lastNonConfigurationChildInstances, config);
...
}
...
}
.....
}

1.通过Instrumention.newAtivity 新建一个Activity对象

2.新建了一个ContextImp 对象, 并且进行初始化。设置Ativity对象为它的所属对象

3、调用Acctivity.attach 函数建Activity 和Context对象的对象关系,代码如下

final void attach(Context context,ActivityThread aThread,
Instrumentation instr,IBinder token,int ident,
Application application,Intent intent,ActivityInfo info,
CharSequence title,Activity parent,String id,
Object lastNonConfigurationInstance,
HashMap<String,Object> lastNonConfigurationChildInstances,
Configuration config){
attachBaseContext(context);
mWindow =PolicyManager.makeNewWindow(this);
mWindow.setCallback(this);
.....
}

情景分析三:Apliation对象和ContextImp对象的关系建立

通过startService或者bindService时,如果系统检测到需要新创建一个Service实例,就会回调handleCreateService()方法,完成相关数据操作。handleCreateService()函数位于 ActivityThread.java类,如下:

//创建一个Service实例时同时创建ContextIml实例
private final void handleCreateService(CreateServiceData data){
...
//创建一个Service实例
Service service = null;
try{
java.lang.ClassLoader cl = packageInfo.getClassLoader();
service =(Service) cl.loadClass(data.info.name).newInstance();
}catch(Exception e){
}
...
ContextImpl context =newContextImpl();//创建一个ContextImpl对象实例
context.init(packageInfo, null,this);//初始化该ContextIml实例的相关属性
//获得我们之前创建的Application对象信息
Application app = packageInfo.makeApplication(false, mInstrumentation);
//将该Service信息传递给该ContextImpl实例
context.setOuterContext(service);
service.attach(context, this, data.info.name, data.token, app, ActivityManagerNative.getDefault());
...
}

1. 通过反射创建一个Service对象

2. 新建了一个ContextImp 对象, 并且进行初始化。设置Servicce对象为它的所属对象

3. 调用Service.attach 函数建立Service和Context对象的对象关系,代码如下

public final void attach(Context context,ActivityThread thread,String className,IBinder token, Application application,Object activityManager){
attachBaseContext(context);
mThread = thread;// NOTE: unused - remove?
mClassName = className;
mToken = token;
mApplication = application;
mActivityManager =(IActivityManager)activityManager;
mStartCompatibility = getApplicationInfo().targetSdkVersion
<Build.VERSION_CODES.ECLAIR; }

关于ContextImp的源码分析的更多相关文章

  1. ABP源码分析一:整体项目结构及目录

    ABP是一套非常优秀的web应用程序架构,适合用来搭建集中式架构的web应用程序. 整个Abp的Infrastructure是以Abp这个package为核心模块(core)+15个模块(module ...

  2. HashMap与TreeMap源码分析

    1. 引言     在红黑树--算法导论(15)中学习了红黑树的原理.本来打算自己来试着实现一下,然而在看了JDK(1.8.0)TreeMap的源码后恍然发现原来它就是利用红黑树实现的(很惭愧学了Ja ...

  3. nginx源码分析之网络初始化

    nginx作为一个高性能的HTTP服务器,网络的处理是其核心,了解网络的初始化有助于加深对nginx网络处理的了解,本文主要通过nginx的源代码来分析其网络初始化. 从配置文件中读取初始化信息 与网 ...

  4. zookeeper源码分析之五服务端(集群leader)处理请求流程

    leader的实现类为LeaderZooKeeperServer,它间接继承自标准ZookeeperServer.它规定了请求到达leader时需要经历的路径: PrepRequestProcesso ...

  5. zookeeper源码分析之四服务端(单机)处理请求流程

    上文: zookeeper源码分析之一服务端启动过程 中,我们介绍了zookeeper服务器的启动过程,其中单机是ZookeeperServer启动,集群使用QuorumPeer启动,那么这次我们分析 ...

  6. zookeeper源码分析之三客户端发送请求流程

    znode 可以被监控,包括这个目录节点中存储的数据的修改,子节点目录的变化等,一旦变化可以通知设置监控的客户端,这个功能是zookeeper对于应用最重要的特性,通过这个特性可以实现的功能包括配置的 ...

  7. java使用websocket,并且获取HttpSession,源码分析

    转载请在页首注明作者与出处 http://www.cnblogs.com/zhuxiaojie/p/6238826.html 一:本文使用范围 此文不仅仅局限于spring boot,普通的sprin ...

  8. ABP源码分析二:ABP中配置的注册和初始化

    一般来说,ASP.NET Web应用程序的第一个执行的方法是Global.asax下定义的Start方法.执行这个方法前HttpApplication 实例必须存在,也就是说其构造函数的执行必然是完成 ...

  9. ABP源码分析三:ABP Module

    Abp是一种基于模块化设计的思想构建的.开发人员可以将自定义的功能以模块(module)的形式集成到ABP中.具体的功能都可以设计成一个单独的Module.Abp底层框架提供便捷的方法集成每个Modu ...

随机推荐

  1. python基础一 day17 初识递归

    #递归函数 # 了解什么是递归 : 在函数中调用自身函数 # 最大递归深度默认是997/998 —— 是python从内存角度出发做得限制 # 能看懂递归 # 能知道递归的应用场景 # 初识递归 —— ...

  2. Python实现进度条小程序

    一.print()参数介绍 1.end:指定打印结束后添加的字符,默认值为换行符 for j in range(3): print('hello world') for i in range(3): ...

  3. python linecache模块读取文件用法详解

    linecache模块允许从任何文件里得到任何的行,并且使用缓存进行优化,常见的情况是从单个文件读取多行. linecache.getlines(filename) 从名为filename的文件中得到 ...

  4. 散列表的ASL计算

    题目: 已知关键字序列为{30,25,72,38,8,17,59},设散列表表长为15.散列函数是H(key)=key MOD 13,处理冲突的方法为二次探测法Hi= ( H(key) + di )m ...

  5. SpringBoot日志输出至Logstash

    1.springboot项目pom.xml文件下添加如下配置 2.resources目录下创建logback-spring.xml文件 <?xml version="1.0" ...

  6. SpringSecurity项目报错

    启动时,提示: Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory be ...

  7. 【Python】剑指offer 14:剪绳子

    题目:给你一根长度为n的绳子,请把绳子剪成m段 (m和n都是整数,n>1并且m>1)每段绳子的长度记为k[0],k[1],-,k[m].请问k[0]k[1]-*k[m]可能的最大乘积是多少 ...

  8. 20181225 基于TCP/IP和基于UDP/IP的套接字编程

    一.TCP/IP的套接字编程 服务器端代码: import  socket​server = socket.socket() # 默认是基于TCP# 基于TCP的对象serve=socket.sock ...

  9. 算法图解之大O表示法

    什么是大O表示法 大O表示法可以告诉我们算法的快慢. 大O比较的是操作数,它指出了算法运行时间的增速. O(n) 括号里的是操作数. 举例 画一个16个格子的网格,下面分别列举几种不同的画法,并用大O ...

  10. [BZOJ3312][USACO]不找零(状压DP)

    Description 约翰带着 N 头奶牛在超市买东西,现在他们正在排队付钱,排在第 i 个位置的奶牛需要支付 Ci元.今天说好所有东西都是约翰请客的,但直到付账的时候,约翰才意识到自己没带钱,身上 ...