Android性能优化

性能优化之App 启动时间

2019-10-19  本文已影响0人  程序员Android1

和你一起终身学习,这里是程序员 Android

本篇文章主要介绍 Android 开发中的部分知识点,通过阅读本篇文章,您将收获以下内容:

一、应用启动时间概述
二、应用启动机制概述
三、冷启动
四、App的创建
五、App Activity的创建
六、热启动
七、暖启动
八、检测和诊断app 启动问题
九、如何分析app 启动时间
十、CPU Profiler
十一、App 启动时间常见问题举例
十二、分析诊断 app 启动时间
十三、添加启动屏Theme

一、应用启动时间概述

用户期望应用程序能够快速响应并快速加载。启动时间慢的应用程序不仅不能满足此期望,而且可能会使用户感到失望。这种糟糕的体验可能会导致用户在Play商店中对您的应用进行差评,甚至卸载您的应用。

本文档提供了可帮助您优化应用程序启动时间的信息。首先说明App 内部启动过程。然后讨论如何分析App启动性能。最后,它描述了一些常见的App启动问题,并提供了有关如何解决这些问题的提示。

二、 应用启动机制概述

应用程序启动可以分以下三种状态,分别如下:冷启动,热启动、暖启动。

冷启动:您的应用将从头开始,App进程从无到有。在其他状态下,系统需要将正在运行的应用程序从后台移到前台。我们建议您始终基于冷启动的假设进行优化。这样做也可以改善热启动和暖启动的性能。

为了优化您的应用程序以使其快速启动,了解每种状态下系统和应用程序级发生的情况以及它们之间的交互方式非常有用。

三、冷启动

冷启动是指应用程序从头开始,比如设备重启,或者app 进程被杀掉,首次启动App时均为冷启动。冷启动在优化启动时间方面比其他状态更麻烦,因为与其他启动状态相比,此时系统和应用程序要做的工作会很多。

1.冷启动前,系统的主要任务

在冷启动的开始,系统主要进行三个任务。这些任务是:

  1. 加载并启动应用程序。
  2. 启动后立即为该App创建并显示空白的启动窗口。
  3. 创建应用程序流程。

2. 冷启动时候 ,APP的主要任务

一旦系统创建了应用程序流程,该应用程序流程将负责以下阶段:

一旦应用程序进程完成了第一次绘制,系统进程就会交换出当前显示的背景窗口,将其替换为 MainActivity。此时,用户可以开始使用该应用程序。

3.系统和APP之间如何相互切换工作

系统和APP之间相互切换工作流程如下图所示:


图1.可视化表示冷应用程序启动的重要部分

4.在创建应用程序和创建Activity 期间可能会出现性能问题。

如需要优化冷启动问题,可以在创建应用程序和创建Activity 期期间进行查看。

四、App的创建

启动应用程序时,空白的启动窗口会保留在屏幕上,直到系统首次完成绘制应用程序为止。此时,系统进程会换出您应用程序的启动窗口,从而允许用户开始与应用程序进行交互。

如果您App已在Application.onCreate() 方法中重载,则系统会首先调用Application.onCreate()。之后,该应用程序就会运行在主线程(也称为UI线程),并通过创建MainActivity来执行其他任务。此后,系统和应用程序的流程将根据 应用程序生命周期阶段进行

五、App Activity的创建

应用程序创建Activity后,该Activity将执行以下操作:

  1. 初始化值。
  2. 调用构造函数。
  3. 调用 Activity.onCreate() 适合于Activity 当前生命周期状态的回调方法,该 onCreate() 方法对加载时间的影响最大,因为该方法以最高的开销执行工作,比如:加载和填充视图,以及初始化Activity运行所需的对象。

六、热启动

与冷启动相比,热启动应用程序更简单,开销也更低。在热启动中,系统要做的就是将您的Activity置于前台。如果应用程序的所有Activity 仍驻留在内存中,则该应用程序可以直接调用,进而避免重复的对象初始化,布局填充和渲染工作。

但是,如果由于内存调整事件,比如调用清除内存的 onTrimMemory() 方法,则需要热启动事件来重新创建那些对象。

热启动显示的屏幕行为与冷启动场景相同:比如系统进程显示空白屏幕,直到应用程序完成活动呈现为止。

七、暖启动

暖启动包括在冷启动期间发生的部分操作。同时,它显示的开销比热启动还多。有许多可能的状态可以认为是暖启动

1.暖启动举例

八、检测和诊断app 启动问题

Android提供了多种方法来告知您的应用程序有问题,并帮助您进行诊断。Android vitals可以提醒您问题正在发生,并且诊断工具可以帮助您诊断问题。

1. Android vitals

当App的启动时间过长时 ,Android vitals 可以通过Google Play控制台提醒您,从而帮助提高应用的性能。当以下情况时,Android vitals 认为您的应用程序的启动时间过长:

Android vitals不会报告热启动相关的数据。有关Google Play如何收集Android生命数据的信息,请参阅 Play控制台文档。

九、如何分析app 启动时间

为了正确诊断启动时间性能,您可以跟踪显示应用程序启动需要多长时间的指标。

1. initial display 初始化时间

在Android 4.4(API级别19)及更高版本中,logcat包含包含名为的值的输出行Displayed,如需查看,可以搜索关键字DisplayedDisplayed此值表示在启动app进程至完全绘制显示在屏幕上,以及Activity之间调用经过的时间。

2.Display 经过事件如下:

抓取的log日志来类似于以下示例:


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

3. AS 中 过滤 Displayed 方法

从命令行或在终端中跟踪logcat输出,查找显示时间很简单。要在Android Studio中查找显示时间,必须在logcat视图中禁用过滤器,在进行适当的设置后,您可以轻松搜索关键词 Displayed
以查看时间。图2显示了如何禁用过滤器,并在底部的第二行输出中显示了Displayed时间的logcat输出示例。

图2.禁用过滤器,并Displayed在logcat中找到值。

Displayed 在 logcat输出中的指标并不一定捕获加载和显示所有资源的时间,它会忽略布局文件中未引用的资源或应用程序作为对象初始化的一部分创建的资源。它排除了这些资源,因为加载它们是一个内联过程,并且不会阻止应用程序的初始显示。

有时,Displayed在logcat输出中的行包含一个用于总时间的附加字段。例如:


ActivityManager: Displayed com.android.myexample/.StartupTiming: +3s534ms (total +1m22s643ms)

这种情况下,第一次测量启动时间仅仅是Activity第一次绘制时间。

Total时间:是用于测量从 app 进程启动到显示,其中可能包括其他非MainActivity的启动,虽然他们没有启动并且没有在屏幕上显示,但是它在mainActivity 中被调用,故在启动的时候也会被初始化上。
这种**Total模式仅适用于 Single Activity模式。

4. adb Logcat 使用方法

当然了,您还可以通过使用ADB Shell 命令运行您的应用来测量首次显示的时间 。这是一个例子:


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

该Displayed指标与以前一样出现在logcat输出中。您的终端窗口也应显示以下内容:

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

-c-a参数是可选的,让你指定 <category><action> 为意图。

5.reportFullyDrawn() 测量全显示时间

您可以使用 reportFullyDrawn() 方法来测量从App启动到完整显示所有资源以及View 层次结构之间经过的时间。
在应用执行延迟加载的情况下,这可能很有价值。在延迟加载中,应用程序不会阻止窗口的初始绘制,而是异步加载资源并更新View视图层级。

如果由于延迟加载而导致应用的初始显示不完所有资源,那么您可以将所有资源和视图的完成加载和显示视为一个单独的指标:例如,您的UI可能已完全加载,并绘制了一些文本,但尚未显示该应用必须从网络获取的图像。

为了解决此问题,您可以手动调用 reportFullyDrawn() 让系统知道您的Activity 已完成其延迟加载。使用此方法时,logcat显示的值是从创建应用程序对象到 reportFullyDrawn() 调用此刻为止所经过的时间 。这是logcat输出的示例

system_process I/ActivityManager: Fully drawn {package}/.MainActivity: +1s54ms

logcat输出有时包含一个total时间,如 “初始显示时间”中所述

如果您发现显示时间慢于所需时间,则可以继续尝试确定启动过程中的瓶颈。

十、CPU Profiler

查找瓶颈的一种好方法是使用Android Studio CPU Profiler。有关信息,请参阅 使用CPU Profiler检查CPU活动

您还可以通过在应用程序和Activity 的onCreate()方法进行内联跟踪来深入了解潜在的瓶颈。要了解内联跟踪,请参阅 Trace 功能文档systrace概述

十一、 App 启动时间常见问题举例

本节讨论了一些通常会影响应用程序启动性能的问题。这些问题主要涉及初始化应用程序和活动对象以及屏幕加载。

1.过多的应用初始化

当您的代码覆盖Application 对象,并在初始化Application.onCreate 对象时会执行繁重的工作或复杂的逻辑运算,则App启动性能会受到影响。
如果您的应用程序子类执行不需要完成的初始化,则您的应用程序可能是在浪费启动时间。某些初始化可能是完全不必要的:例如,当App 通过Intent 启动时,初始化Main Activity 的状态信息是件错误的选择。通过Intent,该应用程序仅使用先前初始化的状态数据的子集。

应用程序初始化期间如果有 频繁的垃圾回收GC事件、频繁的磁盘I / O,这些都阻碍了初始化过程。Dalvik运行时尤其要考虑垃圾回收机制。Art运行时同时执行垃圾回收,从而最大程度地减少了该操作的影响。

十二、分析诊断 app 启动时间

您可以使用方法跟踪或内联跟踪来尝试诊断问题。

1.方法跟踪

运行CPU Profiler会显示该 callApplicationOnCreate() 方法最终会调用您的com.example.customApplication.onCreate 方法。如果该工具表明这些方法需要很长时间才能完成执行,则应进一步探索以查看正在执行的工作。

2. 内联跟踪

使用内联跟踪来调查可能的罪魁祸首,包括:

3. 解决问题的方法

为了优化性能,我们可以尝试改为创建单例模式,而不是创建全局静态对象,在该模式下,应用仅在首次访问对象时才初始化对象。另外,考虑使用Dagger 这样的依赖项注入框架来创建对象,并且依赖项是在首次注入对象时创建的。

4. 过多的Activity 初始化

Activity 创建通常需要大量的开销工作。这些常见问题包括:

5. 解决问题的方法

有许多潜在的瓶颈,但是两个常见的问题和补救措施如下:

十三、添加屏幕启动Theme

实施主题启动屏幕的常用方法是使用 windowDisablePreview 主题属性关闭启动应用程序时系统进程绘制的初始空白屏幕。但是,与不隐藏预览窗口的应用程序相比,这种方法可能导致启动时间更长。

1.诊断问题

您通常可以通过观察用户启动您的应用程序时响应缓慢来诊断此问题。在这种情况下,屏幕可能似乎冻结了,或者已停止响应输入。

2. 解决方案

我们建议您遵循通用的 Material Design模式,而不是禁用预览窗口 。您可以使用Activity的 windowBackground主题属性为开始的活动提供一个简单的自定义可绘制对象。

例如,您可以创建一个新的可绘制文件,并从布局XML和应用清单文件中引用它,如下所示:

3.布局XML文件

<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>

4.Manifest.xml 文件

<activity ...
android:theme="@style/AppTheme.Launcher" />

调用方法
只需要在super.onCreate() 方法 的setContentView()之前设置样式setTheme(R.style.AppTheme)即可。

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);
    // ...
  }
}

友情推荐:
Android 干货分享

至此,本篇已结束,如有不对的地方,欢迎您的建议与指正。同时期待您的关注,感谢您的阅读,谢谢!

上一篇 下一篇

猜你喜欢

热点阅读