前言
本文作为Activity启动流程的第二部分内容将接着Activity启动流程(一)继续讲解,在上一部分中我们了解到了在启动过程中将会对这个Intent进行检查,任务栈之间的切换是否要创建新的任务栈,收集并验证这个Activity的权限,以及一系列初始化操作等等。关于第二部分内容我会说的更加详细一点,大家可以结合代码注释和文字部分一起阅读方便理解。
目录
流程讲解
本篇接着第一步部分内容,将会来到ApplicationThread
的scheduleLaunchActivity
方法,ApplicationThread
是ActivityThread
的一个内部类,ActivityThread
是一个很重要的类,四大组件的启动都会经过它,Android APP进程的初始类,它的main
函数是这个APP进程的入口,主线程也是从main
函数开始的。下面我们来看一下scheduleLaunchActivity方法
1. scheduleLaunchActivity
public final class ActivityThread {
private class ApplicationThread extends IApplicationThread.Stub {
@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);
// 作用:更新当前进程的状态
// 方法分析:
// a.参数procState描述的是进程当前的状态。
// b.当前的进程状态与之前的进程不一致的时候,调用了 VMRuntime.getRuntime().updateProcessState(dalvikProcessState);
// c.调用的这个方法就是为了ART在Foreground GC和Background GC之间切换。
// ActivityThread的内部类
ActivityClientRecord r = new ActivityClientRecord();
//把参数都配置到ActivityClientRecord里面 其中的token就是这个activity的唯一标示
r.token = token;
r.ident = ident;
r.intent = intent;
...省略了部分参数配置
r.overrideConfig = overrideConfig;
updatePendingConfiguration(curConfig);
// 更新配置信息,配置信息里面就包括屏幕大小,方向,语言,输入模式这些都属于配置信息
>>> 定位一下这个Handler消息
sendMessage(H.LAUNCH_ACTIVITY, r);
// 发送一条handlerMessage消息,并把ActivityClientRecord带过去
}
}
}
从scheduleLaunchActivity()
这个方法可以看出,首先它调用了另一个函数updateProcessState()
来更新当前的进程状态只有在进程不一致时才会更新,对于进程的类别在ActivityManager
里面一共定义了19种(8.0的ActivityManager)感兴趣的可以到ActivityManager
去看一下,这里不做深入说明。紧接着会new一个ActivityClientRecord
并把传递过来的参数赋值给它的成员变量,用来保存Activity
,IBinder
,Intent
,Window
等这些对象参数。在方法的最后发送了一条handlerMessage
消息,并把ActivityClientRecord
带了过去。跟踪这条Message
来到如下方法。
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what) {
// 就是这条消息
case LAUNCH_ACTIVITY: {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
r.packageInfo = getPackageInfoNoCheck(
r.activityInfo.applicationInfo, r.compatInfo);
>>> 调用了这个方法
handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
上述代码很简单接收到LAUNCH_ACTIVITY这条 Message
之后调用了handleLaunchActivity
方法
2. handleLaunchActivity
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
unscheduleGcIdler();
// 如果后台在做GC准备的话,但是现在我现在要启动了,所以跳过对这个任务的 GC操作
mSomeActivitiesChanged = true;
if (r.profilerInfo != null) {
mProfiler.setProfiler(r.profilerInfo);
mProfiler.startProfiling();
}
// Make sure we are running with the most recent config.
// 确保我们正在运行最新的配置。
handleConfigurationChanged(null, null);
if (localLOGV) Slog.v(
TAG, "Handling launch of " + r);
// Initialize before creating the activity
WindowManagerGlobal.initialize();
// 作用:初始化一个WindowManagerServer
// 重点关注1:
Activity a = performLaunchActivity(r, customIntent);
if (a != null) {
r.createdConfig = new Configuration(mConfiguration);
reportSizeConfigurations(r);
Bundle oldState = r.state;
// 重点关注2:
handleResumeActivity(r.token, false, r.isForward,
!r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);
} else {
...
}
}
这段代码也很简单,在创建这个活动之前先确保WindowManagerService
已经初始化,之后就会调用Activity
的生命周期,设置主题,初始化等相关工作。 下面将对我在代码里标记的重点关注进行讲解performLaunchActivity和handleResumeActivity这两个方法。我们先来看performLaunchActivity(r, customIntent);
这个方法,其中参数r是ActivityClientRecord
,它是通过Handle
发送Message
带过来的obj
对象,customIntent
传递过来为null,具体实现请接着往下看
2.1 performLaunchActivity
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
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) {
// 检索与意图相关联的具体组件为null的话
// 不过如果是启动新的activity的话,基本不可能,因为在前面的流程中就已经设置匹配好了
component = r.intent.resolveActivity(
mInitialApplication.getPackageManager());
r.intent.setComponent(component);
// 再通过PackageManager找相关联的具体组件
}
if (r.activityInfo.targetActivity != null) {
// targetActivity是这个activity的别名
component = new ComponentName(r.activityInfo.packageName,
r.activityInfo.targetActivity);
// 别名不为null的话重新再设置它的具体组件
}
ContextImpl appContext = createBaseContextForActivity(r);
// 创建activity的上下文context
Activity activity = null;
try {
//这部分通过mInstrumentation反射一个Activity
java.lang.ClassLoader cl = appContext.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
r.intent.prepareToEnterProcess();
if (r.state != null) {
r.state.setClassLoader(cl);
}
} catch (Exception e) {
...
}
}
try {
//>>>> 分析1:
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
// 获取Application对象
if (activity != null) {
// 正常情况下不可能为null的
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
// 拿到这个activity配置的lable标签的value
Configuration config = new Configuration(mCompatConfiguration);
if (r.overrideConfig != null) {
// r.overridConfig 表示activity启动的时覆盖的配置
config.updateFrom(r.overrideConfig);
// 作用:更新覆盖配置
// 方法分析:判断这个overrideConfig配置对象和自己本身的配置相比那些字段发生了变化
// 有变化就更新,无变化或字段为空则不更新,比如屏幕宽高多少,横屏还是竖屏,是否弹出软键盘,输入类型等
}
...
//>>> 分析2
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, r.configCallback);
// 调用activity的attach方法
if (customIntent != null) {
// 参数为null下面不执行
activity.mIntent = customIntent;
}
r.lastNonConfigurationInstances = null;
checkAndBlockForNetworkAccess();
activity.mStartedActivity = false;
int theme = r.activityInfo.getThemeResource();
if (theme != 0) {
activity.setTheme(theme);
// 设置主题
}
activity.mCalled = false;
// 下面这个if else 都会回调activity的onCreate方法关键是这个判断
// 判断这个Activity在manifest中配置的persistableMode是不是persistAcrossReboots默认值为persistRootOnly
// 说明:
// 使用persistAcrossReboots属性声明的活动将在onSavedInstanceState()
// 中提供一个PersistableBundle,这些活动可以使用这个PeristableBundle来保存它们的状态。
// 然后,在重新启动之后,将在其onCreate()方法中向活动提供那个PersistableBundle。
// PersistableBundle它可以和Bundle一样保存数据
if (r.isPersistable()) {
// 默认情况走else
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
// 调用activity的onCreate方法
}
if (!activity.mCalled) {
// mCalled在activity的onCreate方法里面设置为了true
// 如果它这个时候还是false的话说明没有调用onCreate方法
// 分析:强势要求重写onCreate方法时调用super.onCreate()
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;
}
// 这个if里面会执行activiy的onRestoreInstanceState函数
if (!r.activity.mFinished) {
if (r.isPersistable()) {
// r.isPersistable() 这个在上面说过了
if (r.state != null || r.persistentState != null) {
mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,
r.persistentState);
// 调用activity的onRestoreInstanceState(Bundle savedInstanceState, PersistableBundle persistentState)
// 并且在方法里面重载onRestoreInstanceState(savedInstanceState);
}
} else if (r.state != null) {
mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
// 调用activity的onRestoreInstanceState(Bundle savedInstanceState)
}
}
if (!r.activity.mFinished) {
activity.mCalled = false;
// 改为false
if (r.isPersistable()) {
// r.isPersistable() 这个在上面说过了
mInstrumentation.callActivityOnPostCreate(activity, r.state,
r.persistentState);
// 调用activity的onPostCreate(Bundle savedInstanceState, PersistableBundle persistentState)
// 但是还是会重载else的activity回调我把代码贴出来方便理解
// public void onPostCreate(@Nullable Bundle savedInstanceState,
// @Nullable PersistableBundle persistentState) {
// onPostCreate(savedInstanceState);
// }
} else {
mInstrumentation.callActivityOnPostCreate(activity, r.state);
// 调用activity的onPostCreate( Bundle savedInstanceState)
}
if (!activity.mCalled) {
// 在上一个if里回调的onPostCreate里面已经将mCalled改为true了
// 分析:强制要求在重写onPostCreate的时候写上super.onPostCreate()
throw new SuperNotCalledException(
"Activity " + r.intent.getComponent().toShortString() +
" did not call through to super.onPostCreate()");
}
}
}
r.paused = true;
mActivities.put(r.token, r);
// 最后把ActivityClientRecord的保存到map集合
} catch (SuperNotCalledException e) {
throw e;
} catch (Exception e) {
...
}
return activity;
}
从上面代码来看,先检索了一遍这个Intent
的ComponentName
它是这个意图相关的具体组件,如果这个Activity
设置过别名的话就以这个别名为Intent
的ComponentName
,紧接着就更新了它的覆盖配置准备启动,随后便是调用Activity
的生命周期方法了attach
→ onCreate
→ onStart
如果它是重新恢复或者是进行了横竖屏切换还会调用onRestoreInstanceState
方法,随后调用onPostCreate
在方法的最后保存ActivityClientRecord
到map
集合中key为token,token是一个IBinder,IBinder可以方便IPC通信,这里不做深入说明,主要分析Activity
启动流程的主体脉络,避免深入细节无法自拔,话又说回来不了解整体脉络,又如何深入细节呢。好了这个方法的大概内容就说到这里,可以看我代码注释让你有一个更加清晰的脉络。接着讲解我在代码里面标记的2个分析。先看分析1,获取一个Application
对象位于LoadedApk
类的makeApplication()
方法
2.1.1 makeApplication
/**
* 分析1:
* 重点关注注释里面的三点
*/
public Application makeApplication(boolean forceDefaultAppClass,
Instrumentation instrumentation) {
// 1.判断是否为null这个application是否已经初始化
if (mApplication != null) {
return mApplication;
}
// 调用c的makeApplication方法
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "makeApplication");
Application app = null;
String appClass = mApplicationInfo.className;
if (forceDefaultAppClass || (appClass == null)) {
appClass = "android.app.Application";
}
try {
// 2.如果application没有初始化通过类加载器初始化
java.lang.ClassLoader cl = getClassLoader();
if (!mPackageName.equals("android")) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
"initializeJavaContextClassLoader");
initializeJavaContextClassLoader();
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
appContext.setOuterContext(app);
} catch (Exception e) {
...
}
mActivityThread.mAllApplications.add(app);
// 加载完之后赋值给mApplication
mApplication = app;
if (instrumentation != null) {
try {
// 3.初始化之后通过instrumentation调用 application.onCreate();方法
instrumentation.callApplicationOnCreate(app);
} catch (Exception e) {
...
}
}
// Rewrite the R 'constants' for all library apks.
...
return app;
}
不难看出makeApplication()
方法先判断Application
是否已创建,如果已经创建直接return,这也意味着一个应用只有一个Application对象,否则通过类加载器创建Application
,同样也是Instrumentation
来完成的,前面说过Activity
对象也是由Instrumentation
来创建,创建成功之后系统通过instrumentation
的callApplicationOnCreate
方法来调用Application
的onCreate
方法,以上便是makeApplication
方法的分析
接下来让我们再来看performLaunchActivity方法里调用activity
的attach
方法
2.1.2 attach
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, ActivityConfigCallback activityConfigCallback) {
attachBaseContext(context);
mFragments.attachHost(null /*parent*/);
mWindow = new PhoneWindow(this, window, activityConfigCallback);
mWindow.setWindowControllerCallback(this);
mWindow.setCallback(this);
...
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
...
}
在Activity
的attach
方法里,创建一个Window
,其实就是PhoneWindow
对象,它是Window
的实现类。之后设置这个window
的回调接口,而当前Activity
对这个回调接口做了实现,因此当外界触发这些接口的时候将触发Activity
进行处理,比如我们比较熟悉的onMenuItemSelected
,onWindowFocusChanged
,dispatchTouchEvent
,onContentChanged
等。onContentChanged
表示Activity
的布局文件已经被添加到DecorView
的mContentPartent
中了,于是通知Activity
。在Activity
的onContentChanged
方法是个空实现,我们可以在子Activity
中处理这个回调。再说一点不仅只有Activity
会关联Window
对象,凡是有视图的地方就会有Window。Activity
,Dialog
,Toast
等都会关联一个Window
对象。
让我们回过头再来看看handleLaunchActivity
方法里调用的第二个重要的方法handleResumeActivity
2.2 handleResumeActivity
final void handleResumeActivity(IBinder token,
boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
ActivityClientRecord r = mActivities.get(token);
if (!checkAndUpdateLifecycleSeq(seq, r, "resumeActivity")) {
return;
}
unscheduleGcIdler();
// 跳过对这个任务的 GC操作
mSomeActivitiesChanged = true;
// TODO Push resumeArgs into the activity for consideration
r = performResumeActivity(token, clearHide, reason);
// 方法说明:传入token取出保存在map里的ActivityClientRecord执行activity的onResume方法
if (r != null) {
final Activity a = r.activity;
if (localLOGV) Slog.v(
TAG, "Resume " + r + " started activity: " +
a.mStartedActivity + ", hideForNow: " + r.hideForNow
+ ", finished: " + a.mFinished);
final int forwardBit = isForward ?
WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0;
// If the window hasn't yet been added to the window manager,
// and this guy didn't finish itself or start another activity,
// then go ahead and add the window.
boolean willBeVisible = !a.mStartedActivity;
if (!willBeVisible) {
try {
willBeVisible = ActivityManager.getService().willActivityBeVisible(
a.getActivityToken());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
if (r.window == null && !a.mFinished && willBeVisible) {
// 获取activity的PhoneWindow,PhoneWindow在Activity的执行attach的时候创建
r.window = r.activity.getWindow();
// 获取PhoneWindow关联的DecorView,DecorView和PhoneWindow是在Activity的setContentView中关联的
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
ViewManager wm = a.getWindowManager();
// 获取整个窗口的LayoutParams
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
l.softInputMode |= forwardBit;
if (r.mPreserveWindow) {
a.mWindowAdded = true;
r.mPreserveWindow = false;
// Normally the ViewRoot sets up callbacks with the Activity
// in addView->ViewRootImpl#setView. If we are instead reusing
// the decor view we have to notify the view root that the
// callbacks may have changed.
ViewRootImpl impl = decor.getViewRootImpl();
if (impl != null) {
impl.notifyChildRebuilt();
}
}
if (a.mVisibleFromClient) {
if (!a.mWindowAdded) {
//标记根布局DecorView已经添加到窗口
a.mWindowAdded = true;
// 将根布局DecorView以当前Window的布局参数
// 添加到当前Activity的窗口的wm上面
// wm变量是ViewManager,它是一个接口其实现类是WindowManagerImpl
wm.addView(decor, l);
} else {
a.onWindowAttributesChanged(l);
}
}
} else if (!willBeVisible) {
if (localLOGV) Slog.v(
TAG, "Launch " + r + " mStartedActivity set");
r.hideForNow = true;
}
...
} else {
...
}
}
从上述代码的内容来看,里面调用了performResumeActivity
这个方法,这个方法将会调用Activity
的onResume
方法。在onResume
之后调用activity.getWindow()
拿到Window
对象,接着调用Window
的getDecorView
拿到它所关联的DecorView
。前面的Window
就是PhoneWindow
在Activity
执行attach
的时候就说过了,同时它也是在那里初始化的。而其中它所关联的DecorView
是一个FrameLayout
,它包含两个子View
。TitleBar
和Content
其中TitleBar
会受主题的影响而显示或者隐藏,Content
也是一个FrameLayout
负责承载布局View
,通过Activity
的setContentView()
方法设置它的直接子View
。之后有这行代码wm.addView(decor, l)
,其wm
是一个接口ViewManager
,它的实现类是WindowManagerImpl
所以将会调用WindowManagerImpl
的addView
方法。到了addView
方法之后就是关于View
的绘制一块了这个我后续再讲,绘制完之后界面就会展现在我们的视线中了,所以这也是为什么在onResume
方法中不能立刻就拿到View
的宽和高的原因,因为在handleResumeActivity
这个方法里面是先调用Activity
的onResume
方法,之后才调用wm.addView
方法进行View
的绘制和测量。下面我再放张Activity
创建到布局显示的生命周期图如下:
3.生命周期图
Activity创建过程的生命周期4.总结
- 本文给大家讲解了Activity启动流程的第二部分内容,从scheduleLaunchActivity方法到HandleLaunchActivity方法以及各生命周期在哪里调用我相信您已经了解了,觉得对您有帮助请点赞!
网友评论