App启动速度优化

一、概述

要优化App的启动速度,首先需要了解App的启动流程。在Android系统中,系统会为每一个应用开辟一个Linux进程,默认情况下应用都运行在自己的进程中。

一个完整的App启动流程也包含进程的创建过程,关于进程(Application),Google在解释文档中描述为:

By default, every application runs in its own Linux process. Android starts the process when any of the application’s components need to be executed, then shuts down the process when it’s no longer needed or when the system must recover memory for other applications.

也就是说:

  • 当用户要启动App中任意一个组件时,系统都会首先启动这个应用的进程
  • 在适当的时候,系统会关闭这个进程

那么,当用户点击桌面图标启动一个应用界面时,底层的完整流程如下:

  1. Click事件
  2. Launcher调用startActivity()
  3. ActivityManagerService判断进程不存在,则启动进程,否则直接跳到最后一步
  4. Zygote进程Fork子进程ActivityThread,并返回进程id
  5. ActivityThread调用Looper.loop()开启消息循环
  6. ActivityThread加载Application类并绑定进程
  7. 实例化目标Activity并启动

从上面的流程图可以得出

  • 如果App进程不存在,则需要执行3,4,5,6步,我们称之为“冷启动”,一般是首次启动,或者进程被杀死后;
  • 如果App进程存在,则直接实例化并启动目标Activity,我们称之为“温启动”,一般发生在应用退出后,进程被杀前;
  • 还有一种情况,如果进程和目标Activity都存在,只是切到后台,我们称之为“热启动”,如按了Home键。

 

二、检测App启动速度

测量App启动时间的方法很多,常用的有两种(以启动腾讯新闻为例):

(1)过滤Displayed log

启动App时,系统会打印相关log,一般tag为 "ActivityManager" 或 "ActivityTaskManager"

01-25 15:12:19.006  1042  2934 I ActivityTaskManager: START u0 {act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.tencent.news/.activity.SplashActivity bnds=[540,806][792,1146]} from uid 10089 ,pid=2941
01-25 15:12:19.027  1042  3889 I ActivityTaskManager: The Process com.tencent.news Already Exists in BG. So sending its PID: 11291
01-25 15:12:19.028  1042  3889 W ActivityTaskManager: Tried to set launchTime (0) < mLastActivityLaunchTime (16006291)
01-25 15:12:19.165  1042  1179 I ActivityTaskManager: Displayed com.tencent.news/.activity.SplashActivity: +121ms

从第二行可以看出,进程已存在于后台,所以此次启动是“温启动”,启动时间为121ms。

我们在多任务中杀死该进程后再次启动:

01-25 15:15:04.693  1042  3838 I ActivityTaskManager: START u0 {act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.tencent.news/.activity.SplashActivity bnds=[540,806][792,1146]} from uid 10089 ,pid=2941
01-25 15:15:05.233  1042  1179 I ActivityTaskManager: Displayed com.tencent.news/.activity.SplashActivity: +506ms

此次启动为“冷启动”,耗时506ms。

(2)命令行

可以通过如下命令行检测启动时间:

adb shell am start -W 包名/Activity名

依然以腾讯新闻为例:

$ adb shell am start -W   com.tencent.news/.activity.SplashActivity
Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.tencent.news/.activity.SplashActivity }
Status: ok
LaunchState: WARM
Activity: com.tencent.news/.activity.SplashActivity
TotalTime: 93
WaitTime: 106
Complete

通过“LaunchState:WARM”可知此次启动为“温启动”,耗时为96ms(WaitTime:106包含了前一个应用的onPause时间)。

再次通过多任务杀死应用后启动:

$ adb shell am start -W   com.tencent.news/.activity.SplashActivity
Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.tencent.news/.activity.SplashActivity }
Status: ok
LaunchState: COLD
Activity: com.tencent.news/.activity.SplashActivity
TotalTime: 508
WaitTime: 519
Complete

通过“LaunchState:COLD”可知此次启动时“冷启动”,耗时508ms。

我们再试一下按Home键后启动:

$ adb shell am start -W   com.tencent.news/.activity.SplashActivity
Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.tencent.news/.activity.SplashActivity }
Warning: Activity not started, its current task has been brought to the front
Status: ok
LaunchState: HOT
Activity: com.tencent.news/.activity.SplashActivity
TotalTime: 115
WaitTime: 116
Complete

同样的,通过“LaunchState:HOT”可知此次启动为“热启动”,耗时115ms。


 

三、App启动速度优化

当App启动慢的时候,首先要判断是“温/热启动”慢,还是“冷启动”慢,如果只是“冷启动”慢,则判断是否是自定义的Application类初始化时执行了过多耗时的方法,可以通过TraceView工具来定位;如果不是Application类初始化的问题,那就可能是测试机型的问题,需要Framework层来解决。不过这种情况一般比较少,目前市面上的机型都是长期优化的结果。大多数启动慢都是App自己处理不当造成的。

关于App启动速度优化主要有两个方面:

  • 减少耗时
  • 优化体验

从App的启动流程可以知道,应用层能优化的地方只有Application和Activity初始化过程。首先,可以通过TraceView工具来定位耗时方法,然后具体问题具体分析。

关于减少耗时的手段无外乎这几种:

  • 延迟加载 / 懒加载
  • 异步线程执行耗时操作,如图片加载、网络访问、IO操作等
  • ViewStub的使用
  • 减少布局层次和嵌套布局

下面说一种市面上常用的优化体验的方法:placeholder UI。所谓placeholder UI就是通过添加一些占位图优化数据加载过程的等待体验。

我们可以在等待第一帧的过程中,通过加入配置来增加体验。我们写一个简单demo,在Activity的onCreate方法中添加模拟耗时方法。

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
for(int i=0;i<100000;i++) { Log.i("111","模拟初始化耗时!"); } }

启动App时,会发现大概有1~2秒白屏时间,这就是我们需要优化体验的地方。

下面我们为App添加一个主题Theme.MyApplication,并且设置window_background属性:

    <application
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.MyApplication">

 

    <style name="Theme.MyApplication" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
        <item name="android:windowBackground">@drawable/welcome_bg_1920</item>
    </style>

再次启动App,发现白屏变成了我们设置的背景图,用户体验明显会好很多。

但是这样会造成OverDraw,我们可以在Activity创建的时候去掉window_background:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        setTheme(R.style.Theme_MyApplication2);//去掉背景
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        for(int i=0;i<100000;i++){
            Log.i("111","模拟初始化耗时!");
        }
    }
    <style name="Theme.MyApplication2" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
        <item name="android:windowBackground">@android:color/transparent</item>
    </style>

 

posted @ 2021-01-25 16:53  西贝雪  阅读(1272)  评论(0编辑  收藏  举报