前言

上一篇文章我们学习了Context关联类和Application Context的创建过程,这一篇我们接着来学习Activity和Service的Context创建过程。需要注意的是,本篇的知识点会和深入理解四大组件系列的部分文章的知识点相重合。

1.Activity的Context创建过程

当我们在Activity中调用startActivity方法时,其实调用的是Context的startActivity方法,如果想要在Activity中使用Context提供的方法,务必要先创建Context。Activity的Context会在Activity的启动过程中被创建,在Android深入四大组件(一)应用程序启动过程(后篇)的第二小节中,讲到了ActivityThread启动Activity的过程,我们就从这里开始分析。
ActivityThread是应用程序进程的核心类,它的内部类ApplicationThread会调用scheduleLaunchActivity方法来启动Activity,scheduleLaunchActivity方法如下所示。

frameworks/base/core/java/android/app/ActivityThread.java

@Override
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
int procState, Bundle state, PersistableBundle persistentState,
List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {
updateProcessState(procState, false);
ActivityClientRecord r = new ActivityClientRecord();
r.token = token;
...
sendMessage(H.LAUNCH_ACTIVITY, r);
}

scheduleLaunchActivity方法会将启动Activity的参数封装成ActivityClientRecord ,sendMessage方法向H类发送类型为LAUNCH_ACTIVITY的消息,并将ActivityClientRecord 传递过去。sendMessage方法的目的是将启动Activity的逻辑放在主线程中的消息队列中,这样启动Activity的逻辑就会在主线程中执行。
H类的handleMessage方法中会对LAUNCH_ACTIVITY类型的消息进行处理,其中调用了handleLaunchActivity方法,而handleLaunchActivity方法中又调用performLaunchActivity方法,这一过程在Android深入理解Context(一)Context关联类和Application Context创建过程已经讲过了,我们来查看performLaunchActivity方法。
frameworks/base/core/java/android/app/ActivityThread.java

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
Activity activity = null;
try {
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);//
...
}
} catch (Exception e) {
...
} try {
...
if (activity != null) {
Context appContext = createBaseContextForActivity(r, activity);//
...
/**
*3
*/
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window);
...
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);//
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
...
} return activity;
}

performLaunchActivity方法中有很多重要的逻辑,这里只保留了Activity的Context相关的逻辑。在注释1处用来创建Activity的实例。注释2处通过createBaseContextForActivity方法用来创建Activity的ContextImpl,并将ContextImpl传入注释3处的activity的attach方法中。在注释4处Instrumentation的callActivityOnCreate方法中会调用Activity的onCreate方法。
我们先来查看注释2出的createBaseContextForActivity方法:
frameworks/base/core/java/android/app/ActivityThread.java

private Context createBaseContextForActivity(ActivityClientRecord r, final Activity activity) {
...
ContextImpl appContext = ContextImpl.createActivityContext(
this, r.packageInfo, r.token, displayId, r.overrideConfig);//
appContext.setOuterContext(activity);//
Context baseContext = appContext;
...
return baseContext;
}

在注释1处调用ContextImpl的createActivityContext方法来创建ContextImpl,注释2处调用了ContextImpl的setOuterContext方法,将此前创建的Activity 实例赋值给ContextImpl的成员变量mOuterContext,这样ContextImpl也可以访问Activity的变量和方法。
我们再回到ActivityThread的performLaunchActivity方法,查看注释3处的Activity的attach方法,如下所示。
frameworks/base/core/java/android/app/Activity.java

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,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor,
Window window) {
attachBaseContext(context);//
mFragments.attachHost(null /*parent*/);
mWindow = new PhoneWindow(this, window);//
mWindow.setWindowControllerCallback(this);
mWindow.setCallback(this);//
mWindow.setOnWindowDismissedCallback(this);
...
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != );//
if (mParent != null) {
mWindow.setContainer(mParent.getWindow());
}
mWindowManager = mWindow.getWindowManager();//
mCurrentConfig = config;
}

在注释2处创建PhoneWindow,它代表应用程序窗口。PhoneWindow在运行中会间接触发很多事件,比如点击事件、菜单弹出、屏幕焦点变化等事件,这些事件需要转发给与PhoneWindow关联的Actvity,转发操作通过Window.Callback接口实现,Actvity实现了这个接口,在注释3处将当前Activity通过Window的setCallback方法传递给PhoneWindow。
注释4处给PhoneWindow设置WindowManager,并在注释5处获取WindowManager并赋值给Activity的成员变量mWindowManager ,这样在Activity中就可以通过getWindowManager方法来获取WindowManager。
在注释1处调用了ContextThemeWrapper的attachBaseContext方法,如下所示。

frameworks/base/core/java/android/view/ContextThemeWrapper.java

@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(newBase);
}

attachBaseContext方法接着调用ContextThemeWrapper的父类ContextWrapper的attachBaseContext方法:

frameworks/base/core/java/android/content/ContextWrapper.java

protected void attachBaseContext(Context base) {
if (mBase != null) {
throw new IllegalStateException("Base context already set");
}
mBase = base;//
}

注释1处的base指的是一路传递过来的Activity的ContextImpl,将它赋值给ContextWrapper的成员变量mBase。这样ContextWrapper的功能就可以交由ContextImpl处理,举个例子:
frameworks/base/core/java/android/content/ContextWrapper.java

@Override
public Resources.Theme getTheme() {
return mBase.getTheme();
}

当我们调用ContextWrapper的getTheme方法,其实就是调用的ContextImpl的getTheme方法。
Activity的Context创建过程就讲到这里。 总结一下,在启动Activity的过程中创建ContextImpl,并赋值给ContextWrapper的成员变量mBase中。Activity继承自ContextWrapper的子类ContextThemeWrapper,这样在Activity中就可以使用ContextImpl了。
下面给出ActivityThread到ContextWrapper的调用时序图。
深入理解Context2_副本.png

2.Service的Context创建过程

Service的Context创建过程与Activity的Context创建过程类似,也是在Service的启动过程中被创建。在Android深入四大组件(二)Service的启动过程 这篇文章的第二节中讲到了ActivityThread启动Service的过程,我们从这里开始分析。
ActivityThread的内部类ApplicationThread会调用scheduleCreateService方法来启动Service,如下所示。
frameworks/base/core/java/android/app/ActivityThread.java

public final void scheduleCreateService(IBinder token,
ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
...
sendMessage(H.CREATE_SERVICE, s);
}

sendMessage方法向H类发送CREATE_SERVICE类型的消息,H类的handleMessage方法中会对CREATE_SERVICE类型的消息进行处理,其中调用了handleCreateService方法:
frameworks/base/core/java/android/app/ActivityThread.java

private void handleCreateService(CreateServiceData data) {
...
try {
if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);//
context.setOuterContext(service);
Application app = packageInfo.makeApplication(false, mInstrumentation);
service.attach(context, this, data.info.name, data.token, app,
ActivityManagerNative.getDefault());//
service.onCreate();
...
} catch (Exception e) {
...
}
}

在注释1处创建了ContextImpl ,并将该ContextImpl传入注释2处service的attach方法中:
frameworks/base/core/java/android/app/Service.java

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;
}

注释1处调用了ContextWrapper的attachBaseContext方法。
frameworks/base/core/java/android/content/ContextWrapper.java

protected void attachBaseContext(Context base) {
if (mBase != null) {
throw new IllegalStateException("Base context already set");
}
mBase = base;
}

attachBaseContext方法在前文已经讲过,这里不再赘述。
Service的Context创建过程就讲解到这里,由于它和Activity的Context创建过程类似,因此,可以参考前文给出的ActivityThread到ContextWrapper的调用时序图。

Android深入理解Context(二)Activity和Service的Context创建过程的更多相关文章

  1. Android开发 ---ContentProvider数据提供者,Activity和Service就是上下文对象,短信监听器,内容观察者

    1.activity_main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayou ...

  2. Android四大组件应用系列——Activity与Service交互实现APK下载

    Servic与Activity相比它没有界面,主要是在后台执行一些任务,Service有两种启动方法startService()和bindService(),startService方式Service ...

  3. Android学习笔记(八)深入分析Service启动、绑定过程

    Service是Android中一个重要的组件,它没有用户界面,可以运行在后太做一些耗时操作.Service可以被其他组件启动,甚至当用户切换到其他应用时,它仍然可以在后台保存运行.Service 是 ...

  4. android学习-IPC机制之ACtivity绑定Service通信

    bindService获得Service的binder对象对服务进行操作 Binder通信过程类似于TCP/IP服务连接过程binder四大架构Server(服务器),Client(客户端),Serv ...

  5. Android开发系列(二十七):使用ProgressDialog创建进度对话框

    进度对话框在寻常的应用中非经常见,比方下载的时候,打开页面的时候.转移文件等等.有环形的.有长条形的. 基本就这两种 创建进度对话框的两种方式: 1.创建ProgressDialog实例,然后调用Pr ...

  6. Android Application中的Context和Activity中的Context的异同

    一.Context是什么: 1.Context是维持Android程序中各组件能够正常工作的一个核心功能类,我们选中Context类 ,按下快捷键F4,右边就会出现一个Context类的继承结构图啦, ...

  7. Android深入理解Context(三)Context完全解析

      1· Context类型        我们知道,Android应用都是使用Java语言来编写的,那么大家可以思考一下,一个Android程序和一个Java程序,他们最大的区别在哪里?划分界限又是 ...

  8. [转]Android之Context和Activity互相转换

    1.context转换为activity Activity activity = (Activity) context; 2.从activity得到context 在activity的方法中用cont ...

  9. Android之Context和Activity互相转换

    1.context转换为activity Activity activity = (Activity) context; 2.从activity得到context 在activity的方法中用cont ...

随机推荐

  1. easyui toopTip,鼠标划过悬浮,显示一个小提示框的方法

    easyui toopTip,鼠标划过悬浮,显示一个小提示框的方法 /*easyui,鼠标划过悬浮,显示一个小提示框的方法*/ function toopTip(idOrClass,showText) ...

  2. EJB3 阶段总结+一个EJB3案例 (1)

    经过一段时时间的学习,对EJB3的相关知识和jboss8的配置有了大概的了解. 网上对EJB的评论很多,基本都是负面的,都表示EJB太过于沉重,不容易维护.但通过这段时间的学习,私下认为,EJB3在某 ...

  3. dubbo学习(1)--简单的入门搭建实例

    转载请注明源文出处:http://www.cnblogs.com/lighten/p/6828026.html 1 简介 dubbo是一个分布式服务框架,由阿里巴巴的工程师开发,致力于提供高性能和透明 ...

  4. 隐型马尔科夫模型(HMM) 简介

    先介绍一下马尔科夫模型: 马尔可夫模型(Markov Model)是一种统计模型,广泛应用在语音识别,词性自动标注,音字转换,概率文法等各个自然语言处理等应用领域.经过长期发展,尤其是在语音识别中的成 ...

  5. Form表单如何可以传递多个值传递List数组对象到后台的解决办法

    举例说明: 后台有一个对象 User ,结构如下: 后台有一个对象 User ,结构如下: public class User{ private String username; private Li ...

  6. 解析ASP.NET Mvc开发之查询数据实例 分类: ASP.NET 2014-01-02 01:27 5788人阅读 评论(3) 收藏

    目录: 1)从明源动力到创新工场这一路走来 2)解析ASP.NET WebForm和Mvc开发的区别 ----------------------------------------------- ...

  7. Javac语法糖之EnumSwitch

    在Switch中可以使用的类型有枚举.字符串类型与整形int类型,下面来具体看这几个类型. 1.switch为枚举类型 枚举类: enum Fruit { APPLE,ORINGE } 调用javac ...

  8. C/C++中的static

    一.静态全局变量 理解static关键字之前首先回顾一下C/C++程序的在内存中的分配情况.从低地址到高地址依次分为:代码区.全局数据区.堆区.栈区.函数之外的全局变量和静态变量(包括全局变量和静态变 ...

  9. shell:syntax error:unexpected end of file/Starting proxy www-balancer: cannot bind socket--转载

    src:http://www.2cto.com/os/201308/238962.html   执行某bash脚本是发生: syntax error: unexpected end of file 主 ...

  10. Node.js数据流Stream之Duplex流和Transform流

    Duplex流一个很好的例子是TCP套接字连接.需要实现_read(size)和_Write(data,encoding,callback)方法. var stream = require('stre ...