Activity启动流程源码实现(七)初始化目标Activity并执行相关生命周期流程
Android四大组件源码实现详解系列博客目录:
Android应用进程创建流程大揭秘
Android四大组件之bindService源码实现详解
Android四大组件之Activity启动流程源码实现详解概要
Android四大组件之Activity启动流程源码实现详解(一)
Android四大组件之Activity启动流程源码实现详解(二)
Activity启动流程(三)- Activity Task调度算法复盘分析
Activity启动流程(四)- Pause前台显示Activity,Resume目标Activity
Activity启动流程(五)- 请求并创建目标Activity进程
Activity启动流程(六)- 注册目标Activity进程到system_server进程以及创建目标Activity进程Application
Activity启动流程(七)- 初始化目标Activity并执行相关生命周期流程
前言
不知不觉Activity启动系列博客已经更新到系列七来了,这其中的不容易和艰辛只有自己知道了。前面的几章主要是重点分析了Activity启动过程中的涉及的前两个阶段请求阶段和进程创建阶段,上述两个阶段成果为我们的Activity的启动和显示构建好了稳定的外部环境和载体,但是革命尚未成功同志仍需努力啊!在这一篇章中我们将重点介绍Android是怎么开启目标Activity生命周期如下小阶段的:
- 真正启动目的端Activity
- 通过反射加载目标Activity
- 执行目标Activity生命周期
- 初始化目标Activity窗口为显示做准备
注意:本篇的介绍是基于Android 7.xx平台为基础的,其中涉及的代码路径如下:
frameworks/base/services/core/java/com/android/server/am/
--- ActivityManagerService.java
--- ProcessRecord.java
--- ActivityRecord.java
--- ActivityResult.java
--- ActivityStack.java
--- ActivityStackSupervisor.java
--- ActivityStarter.java
--- TaskRecord.java
frameworks/base/services/core/java/com/android/server/pm/
--- PackageManagerService.java
frameworks/base/core/java/android/content/pm/
--- ActivityInfo.java
frameworks/base/core/java/android/app/
--- IActivityManager.java
--- ActivityManagerNative.java (内部包含AMP)
--- ActivityManager.java
--- AppGlobals.java
--- Activity.java
--- ActivityThread.java(内含AT)
--- LoadedApk.java
--- AppGlobals.java
--- Application.java
--- Instrumentation.java
--- IApplicationThread.java
--- ApplicationThreadNative.java (内部包含ATP)
--- ActivityThread.java (内含ApplicationThread)
--- ContextImpl.java
并且在后续的源码分析过程中为了简述方便,会将做如下简述:
- ApplicationThreadProxy简称为ATP
- ActivityManagerProxy简称为AMP
- ActivityManagerService简称为AMS
- ActivityManagerNative简称AMN
- ApplicationThreadNative简称ATN
- PackageManagerService简称为PKMS
- ApplicationThread简称为AT
- ActivityStarter简称为AS,这里不要和ActivityServices搞混淆了
- ActivityStackSupervisor简称为ASS
在正式开始今天博客相关源码分析前,还是先奉上今天博客将要涉及到的时序图以便小伙们先从整体上有个清晰的概括,然后再从细节开撸!
我们对上述的时序图简单的来注释一下:
绿色的组件表示的是运行在目标Activity所属进程中
蓝色的组件表示是运行在system_server进程中
Activity所属进程和system_server进程之间通过红色箭头表示的Binder完成了跨进程通信,配合完成了Activity启动的下半场接力赛
紫色箭头表示的是Handler内部信息传递
一. system_server进程真正的启动目标Activity
看到这个标题也许有小伙们心里想了,难不成我们搞了这么久前面的博客都是假启动目标Activity了,这个当然不是了!怎么说呢,打个不恰当的比喻啊,这个就好像你找女朋友,找老婆必须有个前期储备建立感情基础不,而我们前面所做的就是为了此时真正的启动目标Activity打下的夯实基础而已!
好了,我们继续回到前面博客Activity启动流程(六)- 注册目标Activity进程到system_server进程以及创建目标Activity进程Application的章节1.3,在我们的目标Actiivty应用进程起来之后,会继续检查有没有四大组件在等待运行,如果有会继续其运行(这里我么只关注Activity的启动)。
1.1 ASS.attachApplicationLocked(…)
尼玛!这里又是一个attachApplicationLocked方法,是不是搞错了,真没有错!最外层的attachApplicationLocked是针对AMS的,而这里的attachApplicationLocked方法是针对ASS的。
该方法取名为attachApplication(),顾名思义就是给ASS绑定一个应用,那么,ASS中有什么需要被绑定到一个应用进程的呢?如果小伙们是从Actiivity启动的请求阶段一路走过来那就知道当然是AcivityRecord了。我们在启动目标Activity时创建或者复用了一个新的ActivityRecord,并将其挪到了Stack的栈顶位置,当时,ActivityRecord还没有关联到任何进程相关的信息,还不能被迁移到显示状态。当应用进程被创建之后,Activity才有了运行的机会,这时候才会真正调度我们前面的ActivityRecord。
//[ActivityStackSupervisor.java]
boolean attachApplicationLocked(ProcessRecord app) throws RemoteException {
final String processName = app.processName;
boolean didSomething = false;
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = stacks.get(stackNdx);
if (!isFocusedStack(stack)) {
continue;
}
ActivityRecord hr = stack.topRunningActivityLocked();
if (hr != null) {
if (hr.app == null && app.uid == hr.info.applicationInfo.uid
&& processName.equals(hr.processName)) {
try {
//详见章节1.2
if (realStartActivityLocked(hr, app, true, true)) {
didSomething = true;
}
} catch (RemoteException e) {
...
}
}
}
}
}
return didSomething;
}
该方法的实现逻辑与我们前面博客中介绍的ASS的其他方法基本类似:
- 遍历寻找所有ActivityStack和TaskRecord,然后找到目标Activity的ActivityRecord
- 对栈顶的目标ActivityRecord进行操作,将上述作为参数继续调用realStartActivityLocked真正启动目标Activity
这里的realStartActivityLocked是不是有点似曾相识的感觉!是的,在前面博客中Activity启动流程(五)- 请求并创建目标Activity进程的2.1章节中的startSpecificActivityLocked我们有见过它的身影,并且当时的判断条件是是如果目标Activity所属进程已经创建了的话就会直接进入此分支(如果对于此处有所遗忘的小伙们,可以回头看看),看来它很重要啊。我们来强烈围观一下!
1.2 ASS.realStartActivityLocked(…)
此方法很霸气啊,真的启动Activity!感觉有点像我们小时候过年走亲戚,快要出门的时候大声对主人家说,我真的要告辞了啊(意外之意就是主人家,得准备好红包给我们小孩了)!而这里的弦外之音,我们可以理解我就是要开启Activity的相关生命周期了,即我们应用开发者所熟知的onCreate()/onStart()等方法的调度,这应该就是这里真正启动Activity的真正含义吗!
//[ActivityStackSupervisor.java]
final boolean realStartActivityLocked(ActivityRecord r, //目标Activity数据信息
ProcessRecord app,//目标Activity所属进程信息
boolean andResume, //是否执行resume,传入的参数值为true
boolean checkConfig)//是否检查Config配置,传入的参数值为true
throws RemoteException {
...
r.app = app;
...
int idx = app.activities.indexOf(r);
//判断当前要启动的Activty是否在ProcessRecord中有相关的记录,如若没有则把它加到ProcessRecord中
if (idx < 0) {
app.activities.add(r);
}
mService.updateLruProcessLocked(app, true, null);//更新进程Lru
mService.updateOomAdjLocked();//更新进程adj优先级
...
app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
new Configuration(task.mOverrideConfig), r.compat, r.launchedFromPackage,
task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results,
newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo);//详见章节2.1
...
if (andResume) {
stack.minimalResumeActivityLocked(r);
//这里为了方便演示,将上述源码就地展开
//[ActivitStack.java]
void minimalResumeActivityLocked(ActivityRecord r) {
r.state = ActivityState.RESUMED;//设置为RESUMED状态
mResumedActivity = r; //并将ActivityRecord赋给对应的stack的mResumedActivity
...
}
} else {
...
}
...
return true;
}
realStartActivityLocked()方法的逻辑不少,我们这里抽丝剥茧只取一瓢,重点关注如下三点:
- 将目标ActivityRecord和对应的ProcessRecord关联起来,即通过ActivityRecord可以找到对应的ProcessRecord,然后将目标ActivityRecord存入到ProcessRecord数据结构中的activities列表中!真是你中有我,我中有你的典范啊!
- 借助ATP跨进程调用AT中的scheduleLaunchActivity()方法,进而调度启动目标Activity(这个是重点)
- 目标Activity已经调用完onResume()等生命周期流程之后,这时将目标Activity所属的ActivityStack栈中的mResumedActivity设置目标Activity,并且状态置为RESUMED,为后续的Activity相关调度构建好环境
二. 创建并加载目标Activity
如上一切执行妥当以后,system_server进程会通过IApplicationThread跨进程回调到目标Activity应用进程,从而开始驱动目标Actiivity生命周期的运转和执行了,至于IApplicationThread是怎么实现跨进程调用的这里我也不赘述了(这个当然是Binder的功能,分析Android源码Binder是一道必须跨过去的坎啊,并且这个调用的流程在该系列前面的博客中也有详细的分析过,这里就不赘述了,看的多了,不理解应该也大概能懂了)!总之通过app.thread.scheduleLaunchActivity实际上调用的就是目标Activity进程中ActivityThread的内部类ApplicationThread的scheduleLaunchActivity方法中去了。还是放上一下关于IApplicationThread类图关系图吗(这个冷饭都抄了很多次了)!
其调用过程可以使用下面的伪代码来表示:
ATP.scheduleLaunchActivity()--->
BinderProxy.transact() --->
BpBinder.transact()--->
binder驱动传输--->
JavaBBinder.onTransact()--->
ATN.onTransact()--->
ATN.scheduleLaunchActivity(...) --->
ActivityThread.ApplicationThread.scheduleLaunchActivity(...) --->
2.1 ActivityThread.ApplicationThread.scheduleLaunchActivity(…)
//[ActivityThread.java]
private class ApplicationThread extends ApplicationThreadNative {
...
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);
//将AMS传递过来启动目标Activity相关的参数填充ActivityClientRecord 数据结构
ActivityClientRecord r = new ActivityClientRecord();
r.token = token;
r.ident = ident;
r.intent = intent;
r.referrer = referrer;
r.voiceInteractor = voiceInteractor;
r.activityInfo = info;
r.compatInfo = compatInfo;
r.state = state;
r.persistentState = persistentState;
r.pendingResults = pendingResults;
r.pendingIntents = pendingNewIntents;
r.startsNotResumed = notResumed;
r.isForward = isForward;
r.profilerInfo = profilerInfo;
r.overrideConfig = overrideConfig;
updatePendingConfiguration(curConfig);
sendMessage(H.LAUNCH_ACTIVITY, r);
}
...
}
此时的scheduleLaunchActivity()方法在ApplicationThread的Binder线程中执行,在该方法中将AMS传递过来的参数填充ActivityClientRecord数据结构,然后通过ActivityThread.H携带上述参数调用到ActivityThread的主线程中执行处理,而处理上述逻辑的即是handleLaunchActivity()方法!
在ActivityThread中有如下的一个套路,通常AMS中通过Binder远程调用的scheduleXXX方法,经过Handler的传递以后通常会在主线程中的handleXXX进行下一步的处理!
我们接着继续分析,看看handleLaunchActivity()的处理逻辑!
2.2 ActivityThread.handleLaunchActivity(…)加载并开启Activity生命周期
前面的一切付出都是值得的,进入此流程就要真正的加载并开启目标Activity的生命周期了,付出了这么多终于见到了回报和胜利的输光了!
//[ActivityThread.java]
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
unscheduleGcIdler();//GC相关处理
mSomeActivitiesChanged = true;
if (r.profilerInfo != null) {
mProfiler.setProfiler(r.profilerInfo);
mProfiler.startProfiling();
}
//最终回调目标Activity的onConfigurationChanged()
handleConfigurationChanged(null, null);
//获取WMS服务代理端
WindowManagerGlobal.initialize();
//加载目标Activity,并最终回调目标Activity的onCreate
Activity a = performLaunchActivity(r, customIntent);//详见章节2.3
if (a != null) {
r.createdConfig = new Configuration(mConfiguration);
reportSizeConfigurations(r);
Bundle oldState = r.state;
//最终回调目标Activity的onStart,onResume.
handleResumeActivity(r.token, false, r.isForward,
!r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);//详见章节2.4
if (!r.activity.mFinished && r.startsNotResumed) { //这个正常的启动目标Activity不会进入此分支
...
}
} else {
//如果启动目标Activity发生异常则直接finish掉目标Activity
ActivityManagerNative.getDefault()
.finishActivity(r.token, Activity.RESULT_CANCELED, null,
Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
}
}
这里handleLaunchActivity()方法处理的逻辑是什么呢,大概可以分为如下几部分:
- 首先做一些基本的初始化参数设置工作
- 接着调用performLaunchActivity()方法加载目标Activity,并最终回调目标Activity的onCreate()等生命周期方法
- 如果上述步骤执行成功,继续调用handleResumeActivity()方法来处理Activity进入显示状态时需要完成的操作
- 如果步骤二的操作失败,则通知AMS将目标Activity直接finish掉
2.3 ActivityThread.performLaunchActivity(…)加载Activity
这个方法是真正的负责执行目标Activity的加载和启动,是system_server进程负责调度目标Activity启动的落脚点,从此处开始真正进入我们所熟知的Activity生命周期相关流程!
//[ActivityThread.java]
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
//开始构建目标Activity相关信息
ActivityInfo aInfo = r.activityInfo;
if (r.packageInfo == null) {
r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
Context.CONTEXT_INCLUDE_CODE);
}
ComponentName component = r.intent.getComponent();
if (component == null) {
component = r.intent.resolveActivity(
mInitialApplication.getPackageManager());
r.intent.setComponent(component);
}
if (r.activityInfo.targetActivity != null) {
component = new ComponentName(r.activityInfo.packageName,
r.activityInfo.targetActivity);
}
Activity activity = null;
try {
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
//这里为了演示方便,直接把源码展开
//[Instrumentation.java]
public Activity newActivity(ClassLoader cl, String className,
Intent intent)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
return (Activity)cl.loadClass(className).newInstance();
}
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
r.intent.prepareToEnterProcess();
if (r.state != null) {
r.state.setClassLoader(cl);
}
} catch (Exception e) {
...
}
try {
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
if (activity != null) {
//创建目标Activity对应的Context上下文
Context appContext = createBaseContextForActivity(r, activity);
//[ActivityThread.java]
//这里为了演示方便,将其扩展开
private Context createBaseContextForActivity(ActivityClientRecord r, final Activity activity) {
int displayId = Display.DEFAULT_DISPLAY;
try {
displayId = ActivityManagerNative.getDefault().getActivityDisplayId(r.token);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
ContextImpl appContext = ContextImpl.createActivityContext(
this, r.packageInfo, r.token, displayId, r.overrideConfig);
appContext.setOuterContext(activity);
Context baseContext = appContext;
final DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
String pkgName = SystemProperties.get("debug.second-display.pkg");
if (pkgName != null && !pkgName.isEmpty()
&& r.packageInfo.mPackageName.contains(pkgName)) {
for (int id : dm.getDisplayIds()) {
if (id != Display.DEFAULT_DISPLAY) {
Display display =
dm.getCompatibleDisplay(id, appContext.getDisplayAdjustments(id));
baseContext = appContext.createDisplayContext(display);
break;
}
}
}
return baseContext;
}
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
Configuration config = new Configuration(mCompatConfiguration);
if (r.overrideConfig != null) {
config.updateFrom(r.overrideConfig);
}
Window window = null;
if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
window = r.mPendingRemoveWindow;
r.mPendingRemoveWindow = null;
r.mPendingRemoveWindowManager = null;
}
//将上述创建的相关信息,attach到Activity中为后续Activity显示运行做准备
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 (customIntent != null) {
activity.mIntent = customIntent;
}
r.lastNonConfigurationInstances = null;
activity.mStartedActivity = false;
int theme = r.activityInfo.getThemeResource();
if (theme != 0) { //如果在AndroidManifest中有配置Activity主题,则设置主题
activity.setTheme(theme);
}
activity.mCalled = false;
//开始执行目标Activity的onCreate()方法回调
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
if (!activity.mCalled) {
throw new SuperNotCalledException(
"Activity " + r.intent.getComponent().toShortString() +
" did not call through to super.onCreate()");
}
r.activity = activity;
r.stopped = true;
if (!r.activity.mFinished) {
activity.performStart();//执行目标Activity的onStart()方法
r.stopped = false;
}
...
}
r.paused = true;
//将目标Activity相关信息,保存到mActivities中
mActivities.put(r.token, r);
} catch (SuperNotCalledException e) {
throw e;
} catch (Exception e) {
...
}
return activity;
}
我们的performLaunchActivity()方法有干了那些事情,有那些功劳呢,我们来掰持掰持:
-
首先会初始化构建目标Activity相关的一些信息。此处我们目标Activity的创建是通过反射来构建的,这就需要包名、类名等信息,而其中的绝大部分信息已经从系统进程传递到应用进程了,还有些部分信息也都可以通过PackageManager再向系统进程索取;
-
上述相关参数准备完毕OK以后,便可以通过ClassLoader加载到Activity对应的类,通过反射加载
-
接着依次创建目标Activity对应的Application对象,当前条件下并不会创建,因为前面已经有初始化过了Application了,而且Activity应用进程只会对应一个Application
-
接着调用createBaseContextForActivity()方法继续构建目标Activity对应的Context上下文,这里的Activity的Context和前面我们Application的Context最大的不同在于Application的Context只包含了packageInfo,而Activity的context的还包含了displayInfo。所以当需要将Context用在显示相关的场合时,请使用Activtiy作为Context。
不知道我上面的表达清楚了没有!一句话总结就是Application中的Context是不能用来做和UI显示相关的操作!
-
接着调用目标Activity的attach()将前面创建相关的数据结构,传递到目标Activity中
-
接着如果在AndroidManifest中有配置了目标Activity主题,则设置相关主题,否则使用默认的
-
接着调用callActivityOnCreate()方法,进而开始执行目标Activity对象的onCreate方法,至此Actiivty进入其生命周期的开始
-
接着调用performStart(),开始目标Activity生命周期的另一征程onStart()方法
分析至此,小伙们是否有一种酣畅淋漓的冠绝,经过了千辛万苦,总算到Activity.onCreate()这个方法啊!原来我们在应该用开发中的简简单单的几行代码,在Android系统中是经过了这样一番曲折的过程才会被执行!
Activity生命周期相关方法就像是Activity调度过程的冰山一角,对于做应用层的开发人员而言,只需要看到最外层的冰山,就能栩栩如生地把冰山的样子转述出来;然而,意想不到的是,冰山底下宏大的世界,撑起整座冰山的根基却是如此的复杂。为了冰山一角我们的谷歌的哥哥姐姐可没有少做工作啊!
2.4 ActivityThread.handleResumeActivity(…)执行目标Activity的onResume
前面相关的方法执行成功以后,我们的目标Activity对象也已经构建成功,并成功执行完onCreate(), onStart()两个生命周期的调度之后,便进入到这个阶段,执行目标Activity的onResume()生命周期的调度!
//[ActivityThread.java]
final void handleResumeActivity(IBinder token,
boolean clearHide, boolean isForward, boolean reallyResume) {
ActivityClientRecord r = mActivities.get(token);
unscheduleGcIdler();
mSomeActivitiesChanged = true;
// 实际执行应用进程一侧的Activity.onResume()
r = performResumeActivity(token, clearHide);
if (r != null) {
... // 省略与WindownManager相关的窗口操作
if (reallyResume) {
// 通知系统进程,Activity已经处于Resumed状态
ActivityManagerNative.getDefault().activityResumed(token);
}
}
}
这里真正调用目标Activity生命周期的onResume()方法的是performResumeActivity()方法,在这里就不展开分析了,至此我们的整个的Actiivty启动流程到此就结束了!
三. Application/LoadedApk/ContextImpl/Activity关系小结
分析到这里,Activity启动过程中目标Activity应用进程端涉及的相关几个重要角色几乎都已经隆重登场了,特别是Application,LoadedApk,ContextImpl,Activity。而且在前面博客和本篇的博客中都有重点介绍上述几个概念,这里我们有必要梳理梳理这几者之间的关系,其几者之间关系是剪不断理还乱,但是大致上关系如下:
- Application:在一个App应用进程中是有且唯一的,整个应用进程只有一个实例,它和Activity对应的关系是一对多。通常我们在应用程序开发过程中,当我们重写了Application类后,应用程序加载运行的是我们定义的Application类,否则就加载运行默认的Application类。Application拥有自己对应的ContextImpl,它拥有的ContextImpl和Activity对应的ContextImpl的区别就是Application对象所拥有的ContextImpl上下文没有对应的Token和相关显示的displayId,所以Application对应的Applcation不能用于UI相关的显示(Toast除外),否则会抛出如下异常!
-
ContextImpl:这个我们在前面有重点介绍分析过,每个启动的Activity都拥有属于自身的ContextImpl对象,并且Application也拥有自己对应的!ContextImpl记录了应用程序的包名信息、应用程序的资源信息、应用程序的主线程、ContentResolver及Activity对应的IApplicationToken.Proxy,但是Application对象所拥有的ContextImpl上下文就没有对应的Token了!
-
LoadedApk:从我们前面的分析可知LoadedApk类记录了Activity运行所在的ActivityThread、Activity所在的应用程序信息、Activity所在应用进程的包名、Activity所在应用进程的资源路径、Activity应用进程的库路径、Activity所在应用进程的数据存储路径、类加载器和应用程序所使用的资源等信息。并且在一个App应用进程中通常是有且唯一的!
-
Activity:它就不需要我过多介绍了,通常学习Android开发的小伙们最先认识的就是它了。它是我们Android世界的颜值担当,负责界面的呈现!它和ContextImpl是一对一的关系的,每个Activity都拥有自己的ContextImpl!
如上就是几者之间的牵扯关系了,这个大伙在分析源码的时候可以重点关注关注。并且它们之间牵涉了很多的相互引用,理解好了上述的关系对我们理解源码大有裨益!
总结
到此,目标Activity便正式启动,开始进入Activity生命周期,执行完onCreate/onStart/onResume方法,然后开始UI渲染,经过上述一番操作之后目标Activity就可以显示到我们的主界面了!
而到此,我们的Android四大组件之Activity启动流程也就就此完结了!在最后我们从进程的交互角度出发,对我们整个Activity启动流程简单总结一番!在总结之前我们先看它涉及的整体流程图:
目标Actiivyt启动流程如下:
- 发起端进程(可能是第三方App进程也可能是桌面Launcher)调用Binder IPC跨进程通信机制向system_server进程发起startActivity目标Activity请求
- system_server进程在收到发起端进程的请求之后,会做一系列处理为目标Actiivity找到/创建合适的stack和TaskRecord栈,创建目标Actiivty对应的ActivityRecord信息,并且pause前台显示的相关Actiivity
- 我们这里的前提是目标Actiivyt应用进程还没有创建,所以此时system_server进程在处理完上述一切之后,向zygote进程发出请求fork目标Actiivyt进程
- 目标Actiivyt进程被创建之后,通过Binder IPC向sytem_server进程发起attachApplication请求,继续向AMS注册相关数据结构为后续目标Activity进程转变成应用开发所熟知的App进程做相关准备
- 接着system_server进程通过Binder IPC向目标Activity进程发起bindApplication请求
- 目标Actiivyt进程的binder线程(ApplicationThread)在收到请求后,通过handler向主线程发送BIND_APPLICATION消息
- 主线程在收到Message后,通过发射机制创建目标Application,并回调Application.onCreate()等方法
- 上述执行OK以后,system_server进程会继续检查目标Activity进程是否还有Actiivyt待启动(当然有了),接着再通过binder IPC向目标Actiivyt进程发送scheduleLaunchActivity请求;
- 目标Activity进程的binder线程(ApplicationThread)在收到请求后,通过handler向主线程发送LAUNCH_ACTIVITY消息
- 主线程在收到Message后,通过发射机制创建目标Activity,并回调Activity.onCreate()等方法
写在最后
Activity启动流程(七)- 初始化目标Activity并执行相关生命周期流程这里就要告一段落了,整个的Activity的启动也基本宣告完结了!虽然说是基本完结了,但是Activiyt启动过程中涉及的很多知识点并不是到此就已经over了,这个就需要各位小伙们在平时的积累和总结了。在接下来的博客中,我将会重点分析目标Activity的是怎么加载布局以及怎么将布局绘制到我们的终端界面上面的,如果有感兴趣的亲请期待。好了,青山不改绿水长流先到这里了。如果本博客对你有所帮助,麻烦关注或者点个赞,如果觉得很烂也可以踩一脚!谢谢各位了!!