美文网首页Android性能优化
性能优化之App 启动时间

性能优化之App 启动时间

作者: 程序员Android1 | 来源:发表于2019-10-19 10:58 被阅读0次

    和你一起终身学习,这里是程序员 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的主要任务

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

    • 1.创建Application对象。
    • 2.启动主线程。
    • 3.创建MainActivity。
    • 4.填充视图。
    • 5.显示布局。
    • 6.执行初始化绘制。

    一旦应用程序进程完成了第一次绘制,系统进程就会交换出当前显示的背景窗口,将其替换为 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.暖启动举例

    • 用户退出您的应用程序,然后重新启动它。该过程可能继续运行,但此时应用必须重新创建 Activity onCreate()
    • 您的应用程序从系统内存中退出,但是用户又重新启动它,这时需要重新启动 Process 和Activity,但 task 可以从已保存的实例状态传递到 Activity 中的 onCreate()

    八、检测和诊断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 经过事件如下:

    • 启动 app 进程。
    • 初始化对象。
    • 创建并初始化Activity。
    • Inflate填充布局。
    • 第一次绘制您的App。

    抓取的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. 内联跟踪

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

    • 您应用的初始 Application.onCreate() 功能。
    • 您的应用初始化的所有全局单例对象。
    • 在瓶颈期间可能发生的任何磁盘I / O,反序列化或紧密循环。

    3. 解决问题的方法

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

    4. 过多的Activity 初始化

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

    • 填充过大或复杂的布局。
    • 阻止磁盘或网络I / O上的屏幕绘制。
    • 加载和解码位图。
    • 栅格化 VectorDrawable 对象。
    • 初始化活动的其他子系统。

    5. 解决问题的方法

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

    • 视图层次结构越大,应用程序花费的时间就越多。您可以采取两个步骤来解决此问题:
      • 通过减少冗余或嵌套布局来展平视图层次结构。
      • 不在启动过程中填充不需要显示的UI部分。而是将 ViewStub 对象用作占位符,用于应用程序可以在更合适的时间膨胀的子层次结构。
    • 在主线程上进行所有资源初始化也会降低启动速度。您可以按以下方式解决此问题:
      • 移动所有资源初始化,以便应用程序可以在其他子线程上延迟执行它。

    十三、添加屏幕启动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 干货分享

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

    相关文章

      网友评论

        本文标题:性能优化之App 启动时间

        本文链接:https://www.haomeiwen.com/subject/ntxwmctx.html