前言

上一篇文章我们学习了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. 聚类系数可变无标度网络模型Holme-Kim HK模型

    # -*- coding: cp936 -*- import random import networkx as nx from networkx.generators.classic import ...

  2. yolov3源码分析keras(一)数据的处理

    一.前言 本次分析的源码为大佬复现的keras版本,上一波地址:https://github.com/qqwweee/keras-yolo3 初步打算重点分析两部分,第一部分为数据,即分析图像如何做等 ...

  3. ContentProvider类的设计分析

    ContentProvider的类设计很好,Transport作为成员存在,完成Binder的功能,有点像组合模式,把完成转发/通信功能 封装为一个内部类,便于转发外部调用给外部类,这种设计在Andr ...

  4. Android版本分布——2017年5月更新

    Code Name Version API Level Last month This month Change gingerbread(姜饼) 2.3.3——2.3.7 10 0.9% 1.0% 0 ...

  5. mongodb-分组分页

    1, 添加测试数据 @Test public void save() { News n = null; ; i < ; i++) { n = new News(); n.setTitle(&qu ...

  6. C#直接用数字定义背景颜色

    如下: tableLayoutPanel.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte ...

  7. ES6那些事半功倍的新特性(一)

    数组方面 Array.from(xxx):把json格式字符串转换成数组: Array.of(x,x,x):负责把一堆文本或者变量转换成数组 find( ):该方法为实例方法,就是以Array对象开头 ...

  8. Linux系统资源查看 之 资源信息

    1. 系统 版本信息 内核版本 使用 uname 命令: -a : 查看所有系统信息 -r : 查看内核版本信息 -s : 查看内核名称 代码如下: [niesh@niesh ~]$ uname -a ...

  9. Ionic3与Angular4新特性

    之前(17年3月底)Angular4.0.0正式发布,这个月(4月十几号)Ionic3又发布了,很多人看到这个估计都是一脸懵圈,其实,Angular4只是Angular2的后续版本,Ionic3也是I ...

  10. javascript加上标签

    在javascript脚本中可以加上标签,方便javascript程序进行快速定位,标签一般由一个合法的字符名称加上一个冒号组成,标签可以放在任意行的位置,这样可以为该行设置一个标记,然后再 结构体中 ...