在App启动方式中分为三种:冷启动(cold start)、热启动(hot start)、温启动(warm start)
系统不存在App进程(App首次启动或者App被完全杀死)时启动App(后台没有该应用的进程,这时系统会又一次创建一个新的进程分配给该应用),此时,App的启动将经历两个阶段:
1.加载并启动app
2.app启动后,第一时间为app显示一个空白的window
3.创建app进程
系统一旦创建了app进程,app进程就要负责做以下的任务:
1.创建app对象
2.创建ActivityThread
3.创建MainActivity
4.渲染视图
5.执行onLayout
6.执行onDraw
7.完成第一次绘制后,把mainActivity替换已经展示的BackgroundWindow,即空白window。
也就是说冷启动由于系统会又一次创建一个新的进程分配给它。所以会先创建和初始化Application类,再创建和初始化MainActivity类(包含一系列的測量、布局、绘制),最后显示在界面上。
温启动包含在冷启动期间发生的一些操作,它的开销大于热启动(重新走 Activity 的一些生命周期,它不会重新走进程的创建、Application 的生命周期等)。由于app进程依然在,温启动只执行冷启动的第二阶段。例如:
热启动比冷启动简单得多而且开销更低,在热启动时,系统会将Activity从后台切回到前台,如果应用的所有Activity仍旧留在内存中,那么应用可以避免重复创建对象初始化,布局加载和绘制。
如果应用响应了系统内存清理的通知清理了内存,比如回调onTrimMemory(),那么这些被清理的对象在热启动就会被重新创建。也就和冷启动展示在屏幕的行为相同,系统进程会创建一个空白的屏幕直到应用绘制完成显示出Activity。
app启动优化的方向是冷启动。
app启动时,会短暂的一瞬间白屏:
// Set to false to disable the preview that is shown while a new activity
// is being started.
private static final boolean SHOW_APP_STARTING_PREVIEW = true;
void startActivityLocked(ActivityRecord r, ActivityRecord focusedTopActivity,
boolean newTask, boolean keepCurTransition, ActivityOptions options) {
//…… 省略一万行……
if (!isHomeOrRecentsStack() || numActivities() > 0) {
if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
"Prepare open transition: starting " + r);
//…… 省略一万行……
boolean doShow = true;
if (newTask) {
// Even though this activity is starting fresh, we still need
// to reset it to make sure we apply affinities to move any
// existing activities from other tasks in to it.
// If the caller has requested that the target task be
// reset, then do so.
if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
resetTaskIfNeededLocked(r, r);
doShow = topRunningNonDelayedActivityLocked(null) == r;
}
} else if (options != null && options.getAnimationType()
== ActivityOptions.ANIM_SCENE_TRANSITION) {
doShow = false;
}
if (r.mLaunchTaskBehind) {
// Don't do a starting window for mLaunchTaskBehind. More importantly make sure we
// tell WindowManager that r is visible even though it is at the back of the stack.
r.setVisibility(true);
ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
// 如果同时满足,则显示空白屏幕
} else if (SHOW_APP_STARTING_PREVIEW && doShow) {
//……
//显示空白屏幕
r.showStartingWindow(prev, newTask, isTaskSwitch(r, focusedTopActivity));
}
} else {
// If this is the first activity, don't do any fancy animations,
// because there is nothing for it to animate on top of.
ActivityOptions.abort(options);
}
}
在源码在可以看到,显示白屏由两个变量决定SHOW_APP_STARTING_PREVIEW && doShow,SHOW_APP_STARTING_PREVIEW 表示activity启动前是否显示预览;doShow,其默认值为true,但是它由newTask决定,是否为一个全新的activity栈,也就是说,SHOW_APP_STARTING_PREVIEW为true,并且app冷启动,就显示白屏。
那么能不能让用户不显示白屏呢?
由两种方法:
1.禁用app启动时window预览的功能
在主题中为首屏activity添加一个注意禁用window预览的功能,并在manifest中使用
<resources>
<!--Base application theme-->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!--Customize your theme here.-->
<item name="colorPrimary">@color/mainColor</item>
<item name="colorPrimaryDark">@color/red</item>
<item name="colorAccent">@color/black</item>
</style>
<!--禁用预览功能主题-->
<style name="AppSpalshNoPreviewTheme" parent="AppTheme">
<item name="android:windowFullscreen">true</item>
<item name="windowNoTitle">true</item>
<!-- <item name="android:windowContentOverlay">@null</item>-->
<!-- <item name="android:windowBackground">@mipmap/wall</item>-->
<item name="android:windowDisablePreview">true</item>
</style>
</resources>
<style name="AppSpalshNoPreviewTheme" parent="AppTheme">
<item name="android:windowBackground">@mipmap/aliyun</item>
<item name="android:windowFullscreen">true</item>
<item name="windowNoTitle">true</item>
<!-- <item name="android:windowDisablePreview">true</item>-->
</style>