关于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. 操作系统(4)_进程同步_李善平ppt

    生产者进程count++是它的临界区,消费者count--是它的临界区. 经典同步问题,死锁问题,略.

  2. Java - Java 中的三种 ClassLoader

    1.虚拟机类加载器(称为“bootstrap class loader”),它本身没有父类加载器,它负责加载虚拟机的内置类,由于它是用C.C++写的,所以Java无法拿到其class文件,返回的都是空 ...

  3. 项目17-超详细“零”基础kafka入门篇

    分类: Linux服务篇,Linux架构篇   1.认识kafka 1.1 kafka简介 Kafka 是一个分布式流媒体平台 kafka官网:http://kafka.apache.org/ (1) ...

  4. 作业hashlib题目

    '''1.编写用户认证功能,要求如下 1.1.对用户密码加盐处理 1.2.用户名与密文密码存成字典,是以json格式存到文件中的 1.3.要求密用户输入明文密码,但程序中验证的是密文'''import ...

  5. centos7.3网络配置

    一.关闭NetworkManager 默认状态下最小化安装使用NetworkManager这个服务来控制联网的,但是这个配置在配置生产环境服务器时一般不会使用,而是使用系统自带的network服务,更 ...

  6. django之路由分发

    路由分发决定哪一个路由由哪一个视图函数来处理. 注意:django2.0里的re_path和django1.0里的url除了名字不一样,其他都一样. 简单配置 from django.urls imp ...

  7. MySQL的增、删、查、改操作命令

    MySQL的增.删.查.改操作命令: 一.修改mysql数据库密码 格式:mysqladmin -u用户名 -p旧密码 password 新密码. 二.查看 查看多少个数据库:注意 后面带s #查看 ...

  8. 算法训练 Eurodiffusion

    Eurodiffusion /***********并未完全AC***********/ #include<iostream> #include<algorithm> #inc ...

  9. as API一些容易忘记的属性和方法

    1.在flash动画里的一些动态文本会随着动画的执行,有抖动,解决问题的方法: tt为动画里的动态文本,tt.transform.matrix=null;

  10. day23 Model 操作,Form 验证以及序列化操作

    Model 操作 1创建数据库表 定制表名:       普通索引:             创建两个普通索引,这样就会生成两个索引文件   联合索引:           为了只生成一个索引文件,才 ...