Android深入理解Context(二)Activity和Service的Context创建过程
前言
上一篇文章我们学习了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创建过程的更多相关文章
- Android开发 ---ContentProvider数据提供者,Activity和Service就是上下文对象,短信监听器,内容观察者
1.activity_main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayou ...
- Android四大组件应用系列——Activity与Service交互实现APK下载
Servic与Activity相比它没有界面,主要是在后台执行一些任务,Service有两种启动方法startService()和bindService(),startService方式Service ...
- Android学习笔记(八)深入分析Service启动、绑定过程
Service是Android中一个重要的组件,它没有用户界面,可以运行在后太做一些耗时操作.Service可以被其他组件启动,甚至当用户切换到其他应用时,它仍然可以在后台保存运行.Service 是 ...
- android学习-IPC机制之ACtivity绑定Service通信
bindService获得Service的binder对象对服务进行操作 Binder通信过程类似于TCP/IP服务连接过程binder四大架构Server(服务器),Client(客户端),Serv ...
- Android开发系列(二十七):使用ProgressDialog创建进度对话框
进度对话框在寻常的应用中非经常见,比方下载的时候,打开页面的时候.转移文件等等.有环形的.有长条形的. 基本就这两种 创建进度对话框的两种方式: 1.创建ProgressDialog实例,然后调用Pr ...
- Android Application中的Context和Activity中的Context的异同
一.Context是什么: 1.Context是维持Android程序中各组件能够正常工作的一个核心功能类,我们选中Context类 ,按下快捷键F4,右边就会出现一个Context类的继承结构图啦, ...
- Android深入理解Context(三)Context完全解析
1· Context类型 我们知道,Android应用都是使用Java语言来编写的,那么大家可以思考一下,一个Android程序和一个Java程序,他们最大的区别在哪里?划分界限又是 ...
- [转]Android之Context和Activity互相转换
1.context转换为activity Activity activity = (Activity) context; 2.从activity得到context 在activity的方法中用cont ...
- Android之Context和Activity互相转换
1.context转换为activity Activity activity = (Activity) context; 2.从activity得到context 在activity的方法中用cont ...
随机推荐
- Linux CentOS7系统中php安装配置
本篇讲解如何配置php开发环境,让你的php代码可以正常的在网页中运行. 准备工作 linux centos7操作系统 ssh软件 nginx php资源 想要了解更多关于php的内容,请访问: ph ...
- 神策Loagent数据收集 windows部署的坑
部署可以修改bin文件夹下的bat文件.. java改为javaw..无窗口运行 重新启动的时候..要保证上次运行到的日志文件要还在..或者同名文件.. 保证要比之前的文件大些..所以最好是之前的文件 ...
- android IPC 机制 (开发艺术探索)
一.IPC 机制介绍 IPC是Inter-Process Communication的缩写,含义就是进程间通信或者跨进程通信,是指两个进程之间进行数据交换的过程.那么什么是进程,什么是线程,进程和线程 ...
- 隐型马尔科夫模型(HMM)向前算法实例讲解(暴力求解+代码实现)---盒子模型
先来解释一下HMM的向前算法: 前向后向算法是前向算法和后向算法的统称,这两个算法都可以用来求HMM观测序列的概率.我们先来看看前向算法是如何求解这个问题的. 前向算法本质上属于动态规划的算法,也就是 ...
- 安卓的SlidingMenu配置
最近用到了界面的优化,使用SlidingMenu开源库比较方便,为了方便学习,我整理了一下配置过程. 1.准备资料. 首先下载这两个ActionBarSherlock和SlidingMenu,如图:
- Ubuntu各版本的历史发行界面
不多说,直接上干货! 总的网址是:http://releases.ubuntu.com/releases/ 比如,选择的是UbuntuKylin,则点击 http://cdimage.ubuntu. ...
- Jfinal本地eclipse+tomcat运行项目时候遇到错误Exception starting filter
今天想在本地eclipse上启动tomcat让项目在本地运行,但是老是报错类找不到异常. 也可能报其它错误,大概都是classNotFoundException. 九月 19, 2018 5:42:2 ...
- java HashMap源码分析(JDK8)
这两天在复习JAVA的知识点,想更深层次的了解一下JAVA,所以就看了看JAVA的源码,把自己的分析写在这里,也当做是笔记吧,方便记忆.写的不对的地方也请大家多多指教. JDK1.6中HashMap采 ...
- org.springframework.beans.NullValueInNestedPathException
报错代码: HTTP Status 500 - An exception occurred processing JSP page /WEB-INF/views/input.jsp at line 2 ...
- django2.1---中间件
在http请求 到达视图函数之前 和视图函数return之后,django会根据自己的规则在合适的时机执行中间件中相应的方法. Django1.9版本以后中间件的执行流程 1.执行完所有的requ ...