a284628487 / AndroidPoint

Android Note
1 stars 0 forks source link

App Startup Time #5

Open a284628487 opened 6 years ago

a284628487 commented 6 years ago

https://developer.android.com/topic/performance/vitals/launch-time

a284628487 commented 6 years ago

Cold start

冷启动指打开App时,启动一个全新的进程的情况,通常发生在第一次使用应用时、手机重启后第一次打开应用,或者系统把该App进程kill掉了,这几种状态下,启动App的消耗最大。

在冷启动之前,系统做一三件事:

  1. Loading and launching the app.
  2. Displaying a blank starting window for the app immediately after launch.
  3. Createing the app Process.

在创建了app process之后,进程进入可响应状态,

  1. 创建App对象
  2. 加载主线程
  3. 创建MainActivity
  4. 加载View(inflating views)
  5. 显示到屏幕上(Laying out screen)
  6. 开始绘制内容

App进程一旦完成第一次绘制之后,系统进程将当前显示的窗口替换为MainActivity,此时,用户可以开始使用app了。 由此可见,性能问题可能发生的地方:App创建过程或者是MainActivity创建过程

Application creation

当应用程序开始launch,一开始显示一个无内容的白色的启动窗口(starting window),直到应用程序完成了第一次绘制,此时,系统进程将starting window替换为App主页面。 如果重写Applicaiton#onCreate方法,当系统调用onCreate()方法之后,App切换到主线程。

Activity creation

App进程创建Activity之后,Activity开始三项任务

  1. 初始化values
  2. 调用 constructors
  3. 调用生命周期方法,比如onCreate(),onResume()等等

典型的,onCreate()方法可能占用大量的启动时间,因为在onCreate()方法里面,需要加载View,初始化必要的Object对象。

Hot start

热启动相比起冷启动来讲简单并用低耗,热启动时系统做的所有工作就是将Activity从后台切换到前台,如果应用程序app的所有activity仍然在内存中,则app将不全再次创建,避免了(object initialization, layout inflation, rendering).

热启动和冷启动一样,都是系统进程先显示一个白屏的starting window,直到app完成第一次绘制。

Warm start

Warm start对于启动的开销介于Cold start和Hot start之间,以下是两种可能导致Warm start的情况:

  1. 用户退出app,然后又重新进入,此时进程可能仍然在运行,但是app必须重新创建Activity,调用onCreate()方法
  2. 系统从内存中kill掉app,用户重新进入app,此时进程和Activity都需要重新创建,但是Activity创建时,可以用onCreate()方法的参数中获取saved instance bundle,以减小一些开销。

Diagnosing slow startup times

诊断启动时间

Time to initial display

Android 4.4之后,logcat会直接输出某个Activity的启动时间Displayed,这个值表示启动进程到完成第一次绘制的时间长度,即 Cold start中的5步,实测也就是从launch到onResume()的时间。

ActivityManager: Displayed com.android.myexample/.StartupTiming: +3s534ms

也可以通过ADB命令来获取启动时间。

adb [-d|-e|-s <serialNumber>] shell am start -S -W
com.example.app/.MainActivity
-c android.intent.category.LAUNCHER
-a android.intent.action.MAIN

输入结果:

Starting: Intent
Activity: com.example.app/.MainActivity
ThisTime: 2044
TotalTime: 2044
WaitTime: 2054
Complete

-c and -a 参数是可选项,用于指定 category 和 action。

Identifying bottlenecks

  1. MethodTrace
  2. Trace
  3. Systrace

Be aware of common issues

常见问题

Heavy app initialization

Application#onCreate()方法,不适合做大量的工作,比如IO操作,或者做一些不必要的初始化工作。 针对Activity的onCreate()分析,可以使用Method tracint和inline tracing。

Method tracing

使用Method Tracer tool来查看分析callApplicationOnCreate()方法,是否有耗时操作。

Inline tracing

使用 Inline tracing 方法分析以下问题

  1. Your app’s initial onCreate() function.
  2. Any global singleton objects your app initializes.
  3. Any disk I/O, deserialization, or tight loops that might be occurring during the bottleneck.

Heavy activity initialization

Activity的初始化操作,有如下常见的问题

  1. Inflating large or complex layouts.
  2. Blocking screen drawing on disk, or network I/O.
  3. Loading and decoding bitmaps.
  4. Rasterizing VectorDrawable objects.
  5. Initialization of other subsystems of the activity.

针对Activity的onCreate()分析,可以使用Method tracint和inline tracing。

Method tracing

使用Method Tracer tool来查看分析Activity#onCreate()方法,是否有耗时操作。

Inline tracing

同Application。

常见问题及方法

  1. 多层级的View嵌套:减少嵌套层级,对于在launch期间不需要立即显示的View,使用ViewStub。
  2. 加载大量资源:使用懒加载的方法加载资源,先加载View,后更新内容。

Themed launch screens

使用Themed来过渡加载时间,也就是首屏动画,常见的方法是使用 windowDisablePreview theme 属性,来关闭初始 blank screen,然而这种方法可能导致更多的启动时间。

Solutions the problem

根据Material Design规范,可以使用windowBackground theme 属性,来给activity提供一个简单的自定义的drawable。 比如下面是一个例子:

  1. layout xml file:

    <layer-list xmlns:android="http://schemas.android.com/apk/res/android" android:opacity="opaque">
    <!-- The background color, preferably the same as your normal theme -->
    <item android:drawable="@android:color/white"/>
    <!-- Your product logo - 144dp color version of your app icon -->
    <item>
    <bitmap
      android:src="@drawable/product_logo_144dp"
      android:gravity="center"/>
    </item>
    </layer-list>
  2. Manifest file:

<activity ...
android:theme="@style/AppTheme.Launcher" />
  1. theme 最简单的切换theme的方法,是在super.onCreate()setContentView()之前调用setTheme()方法。
public class MyMainActivity extends AppCompatActivity {
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    // Make sure this is before calling super.onCreate
    setTheme(R.style.Theme_MyApp);
    super.onCreate(savedInstanceState);
    // ...
  }
}