Android中的冷启动,热启动和温启动

在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类(包含一系列的測量、布局、绘制),最后显示在界面上。

ActivityThread:负责管理应用程序的生命周期,处理消息队列,处理用户输入事件,调度Activity的创建和销毁等等。

具体来说,ActivityThread会在应用程序启动时会创建一个主线程(也就是UI线程),然后根据AndroidManifest.xml文件中声明的启动Activity,创建一个Activity对象,并通过Binder机制将这个Activity对象传递给ActivityManagerService。Activity还会负责处理Activity的生命周期,比如当用户按下返回键退出当前Activity时,ActivityThread会收到相应的消息,然后销毁当前Activity并恢复上一个Activity的状态。ActivityThread还负责处理其他一些系统事件,比如屏幕旋转、系统资源不足等等,这些事件都会通过消息队列传递给ActivityThread,然后由ActivityThread调度处理。

温启动

温启动包含在冷启动期间发生的一些操作,它的开销大于热启动(重新走 Activity 的一些生命周期,它不会重新走进程的创建、Application 的生命周期等)。由于app进程依然在,温启动只执行冷启动的第二阶段。例如:

  • 比如返回Home后,又继续使用其他的APP,时间久了或者打开的应用多了,之前应用的Activity有可能被回收了,但应用程序必须通过调用 onCreate() 重新创建Activity
  • 应用程序因为内存原因被系统强制退出,然后用户重新启动应用。进程和 Activity 需要被重新启动,但是保存的 Bundle 实例状态会被传递给 onCreate() 使用

热启动

热启动比冷启动简单得多而且开销更低,在热启动时,系统会将Activity从后台切回到前台,如果应用的所有Activity仍旧留在内存中,那么应用可以避免重复创建对象初始化,布局加载和绘制。

如果应用响应了系统内存清理的通知清理了内存,比如回调onTrimMemory(),那么这些被清理的对象在热启动就会被重新创建。也就和冷启动展示在屏幕的行为相同,系统进程会创建一个空白的屏幕直到应用绘制完成显示出Activity。

App启动优化

app启动优化的方向是冷启动。

空白window问题

app启动时,会短暂的一瞬间白屏:

这是我在Application的onCreate里线程休眠1s实现的。但是在实际项目中确实会存在启动白屏时间过长的问题。

为什么会有白屏?看app启动流程加载首屏部分源码:

ActivityStack

kotlin 复制代码
 	// 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中使用

xml 复制代码
<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>

这个时候你会发现点击了app,过了1秒多才启动,因为我们让本来显示的空白预览页面不展示了。

2.给空白首屏Activity设置一个背景

在style.xml中给SplashActivity添加一个新主题,设置一个背景:

kotlin 复制代码
    <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>

会发现点击了之前的空白页面换成了背景图。

从上面冷启动的介绍可知,app启动过程中,会有如下过程

app启动过程中,显示白屏,首屏第一次绘制完成,就会替换白屏。也就是说在首屏显示之前,都是白屏。

所以,要想解决白屏的问题,就要减少白屏显示的时间,也就是说要加快app初始化和首屏绘制的时间。

相关推荐
Jouzzy6 小时前
【Android安全】Ubuntu 16.04安装GDB和GEF
android·ubuntu·gdb
极客先躯7 小时前
java和kotlin 可以同时运行吗
android·java·开发语言·kotlin·同时运行
Good_tea_h9 小时前
Android中的单例模式
android·单例模式
计算机源码社14 小时前
分享一个基于微信小程序的居家养老服务小程序 养老服务预约安卓app uniapp(源码、调试、LW、开题、PPT)
android·微信小程序·uni-app·毕业设计项目·毕业设计源码·计算机课程设计·计算机毕业设计开题
丶白泽15 小时前
重修设计模式-结构型-门面模式
android
晨春计16 小时前
【git】
android·linux·git
标标大人17 小时前
c语言中的局部跳转以及全局跳转
android·c语言·开发语言
竹林海中敲代码17 小时前
Qt安卓开发连接手机调试(红米K60为例)
android·qt·智能手机
木鬼与槐18 小时前
MySQL高阶1783-大满贯数量
android·数据库·mysql
iofomo18 小时前
【Abyss】Android 平台应用级系统调用拦截框架
android·开发工具·移动端