使用 Firebase 性能监控测量加载时间和屏幕渲染

一、简介

最近更新:2021年3月11日

为什么我们需要衡量 Views 的性能?

视图是直接影响用户体验的 Android 应用程序的关键部分。例如,您的 Activity 或 Fragment 包含 UI,其中包含用户与之交互的 View 组件。在 UI 完全绘制在屏幕上之前,用户无法看到整个 UI 内容。缓慢和冻结的屏幕会直接影响用户与您的应用程序的交互并造成糟糕的用户体验。

Firebase 性能监控不是提供这些现成的性能指标吗?

火力性能监控自动捕捉一些业绩数据外的开箱,如您的应用程序的开始时间(即加载时间只有你的第一个活动)和画面渲染性能(即,速度慢,冻结的活动,但不是帧片段)。然而,行业应用通常没有很多 Activity,而是一个 Activity 和多个 Fragment。此外,许多应用程序通常会为更复杂的用例实现自己的自定义视图。所以,这是可以理解如何通过插来测量活动和片段的加载时间和屏幕渲染性能的自定义代码的痕迹在你的应用程序。您可以轻松扩展此 Codelab 以衡量自定义视图组件的性能。

你会学到什么

  • 如何将 Firebase 性能监控添加到 Android 应用
  • 了解 Activity 或 Fragment 的加载
  • 如何检测自定义代码跟踪以测量 Activity 或 Fragment 的加载时间
  • 了解屏幕渲染以及什么是慢速/冻结帧
  • 如何使用指标检测自定义代码跟踪以记录慢速/冻结屏幕
  • 如何在 Firebase 控制台中查看收集的指标

你需要什么

  • Android Studio 4.0 或更高版本
  • Android 设备/模拟器
  • Java 8 或更高版本

2. 开始设置

获取代码

运行以下命令以克隆此 Codelab 的示例代码。这将创建一个文件夹,名为codelab-measure-android-view-performance你的机器上:

$ git clone https://github.com/FirebaseExtended/codelab-measure-android-view-performance.git
$ cd codelab-measure-android-view-performance

如果你的机器上没有 git,你也可以直接从 GitHub 下载代码。

导入measure-view-performance-start项目到Android Studio中。你可能会看到一些编译错误或者一个关于丢失警告google-services.json文件。我们将在此步骤的下一部分中更正此问题。

在本程式码实验室中,我们将使用火力地堡助手插件与火力地堡项目注册我们的Android应用程序,并添加必要的火力地堡配置文件,插件和依赖关系到我们的Android项目-在Android Studio中的一切

将您的应用连接到 Firebase

  1. 您可以进入Android工作室/帮助>检查更新,以确保您使用的Android Studio和火力地堡助理的最新版本。
  2. 选择Tools>火力地堡打开助理窗格。

e791bed0999db1e0.png

  1. 选择性能监控添加到您的应用程序,然后单击开始使用性能监控开始
  2. 单击连接到火力地堡连接你与火力地堡的Android项目(这将打开浏览器中的火力地堡控制台)。
  3. 在火力地堡控制台,单击添加项目,然后输入一个火力地堡项目名称(如果你已经有了一个火力地堡的项目,您可以选择已有的项目,而不是)。点击继续并接受条款创建火力地堡项目和一个新的火力地堡应用。
  4. 下一步,应当看到一个对话框,以新的火力地堡应用程序连接到你的Android Studio项目。

42c498d28ead2b77.png

  1. 早在Android Studio中,在助手窗格中,您应该看到确认您的应用程序连接到火力地堡。

dda8bdd9488167a0.png

向您的应用程序添加性能监控

在Android Studio中的助理窗格中,单击添加性能监控应用程式

您应该看到一个对话框,以接受之后,Android Studio中应同步您的应用程序的更改,以确保所有必要的依赖已被添加。

9b58145acc4be030.png

最后,你应该看到在Android Studio中的助理窗格中所有的依赖性都正确设置成功的消息。

aa0d46fc944e0c0b.png

作为一个附加的步骤中,通过以下在步骤中的说明“(可选)启用调试日志记录”启用调试日志。同样的说明也可用公共文件

3. 运行应用

如果您已成功将应用程序与性能监控 SDK 集成,则项目现在应该可以编译了。在Android Studio中,单击运行>运行“应用”,以构建和运行您的连接的Android设备/仿真器的应用程序。

该应用程序有两个按钮,可将您带到相应的 Activity 和 Fragment,如下所示:

410d8686b4f45c33.png

在此 Codelab 的以下步骤中,您将学习如何衡量 Activity 或 Fragment 的加载时间和屏幕渲染性能。

4. 了解 Activity 或 Fragment 的加载

在这一步中,我们将了解系统在加载 Activity 或 Fragment 期间正在做什么。

了解 Activity 的加载

对于活动,将加载时间定义为时间,当活动对象被创建所有的方式,直到第一帧是完全在屏幕上绘制(这是当你的用户会看到一个完整的用户界面为活动的第一从开始时间)。要衡量您的应用是否完全画,你可以使用reportFullyDrawn()方法来测量应用程序启动和所有资源和视图层次结构的完整显示之间所经过的时间。

在一个高的水平,当你的应用程序调用startActivity(Intent) ,系统自动进行以下的处理。每个过程都需要时间来完成,这会增加 Activity 创建和用户在其屏幕上看到 Activity 的 UI 之间的持续时间。

c20d14b151549937.png

了解 Fragment 的加载

到负荷时间片段被定义为从将片段被连接到它的主机活动一路直到第一帧的片段查看启动活性的相似的在屏幕上绘制完成。

5. 测量一个Activity的加载时间

第一帧的延迟可能会导致糟糕的用户体验,因此了解您的用户所经历的初始加载延迟有多大非常重要。您可以仪器自定义代码跟踪来衡量这个加载时间:

  1. 启动自定义代码跟踪(命名为TestActivity-LoadTime在Activity类),只要在创建活动对象。

测试活动.java

public class TestActivity extends AppCompatActivity {   
    // TODO (1): Start trace recording as soon as the Activity object is created.
    private final Trace viewLoadTrace = FirebasePerformance.startTrace("TestActivity-LoadTime");

    // ...

}
  1. 重写onCreate()回调,并获得由添加的视图setContentView()方法。
@Override     
public void onCreate(Bundle savedInstanceState) {    
    super.onCreate(savedInstanceState);          

    // Current Activity's main View (as defined in the layout xml file) is inflated after this            
    setContentView(R.layout.activity_test);          

    // ...

    // TODO (2): Get the View added by Activity's setContentView() method.         
    View mainView = findViewById(android.R.id.content);     

    // ...
}
  1. 我们提供了一个实现FistDrawListener ,它有两个回调: onDrawingStart()onDrawingFinish()请参阅下面有关详细信息,下一节FirstDrawListener什么可以影响其性能)。注册FirstDrawListener在活动的结束onCreate()回调。你应该停止viewLoadTraceonDrawingFinish()回调。

测试活动.java

    // TODO (3): Register the callback to listen for first frame rendering (see
    //  "OnFirstDrawCallback" in FirstDrawListener) and stop the trace when View drawing is
    //  finished.
    FirstDrawListener.registerFirstDrawListener(mainView, new FirstDrawListener.OnFirstDrawCallback() {              
        @Override             
        public void onDrawingStart() {       
          // In practice you can also record this event separately
        }

        @Override             
        public void onDrawingFinish() {
            // This is when the Activity UI is completely drawn on the screen
            viewLoadTrace.stop();             
        }         
    });
  1. 重新运行应用程序。然后,过滤器“登录跟踪指标”的logcat的。塔上的LOAD ACTIVITY按钮,并查找日志如下所示:
I/FirebasePerformance: Logging trace metric: TestActivity-LoadTime (duration: XXXms)

🎉恭喜!您已成功测量了 Activity 的加载时间并将该数据报告给 Firebase Performance Monitoring。我们稍后将在此代码实验室的 Firebase 控制台中查看记录的指标。

FirstDrawListener 的目的

在正上方的部分,我们注册了一个FirstDrawListener 。的目的FirstDrawListener是当第一帧已经开始,并且结束图进行测量。

它实现了ViewTreeObserver.OnDrawListener并重写onDraw()当查看树即将绘制被调用回调。然后,它封装了结果,以提供两个实用程序回调onDrawingStart()onDrawingFinish()

完整的代码FirstDrawListener可以在此找到程式码实验室中的源代码

6. 测量一个 Fragment 的加载时间

测量 Fragment 的加载时间类似于我们测量 Activity 的方式,但有一些细微的差别。再次,我们将仪器的自定义代码跟踪

  1. 重写onAttach()回调,并开始录制fragmentLoadTrace 。我们将其命名为跟踪Test-Fragment-LoadTime

正如在前面的步骤中所解释的,可以随时创建 Fragment 对象,但只有当它附加到其宿主 Activity 时它才会变为活动状态。

测试片段.java

public class TestFragment extends Fragment {

   // TODO (1): Declare the Trace variable.
   private Trace fragmentLoadTrace;

   @Override
   public void onAttach(@NonNull Context context) {
       super.onAttach(context);

       // TODO (2): Start trace recording as soon as the Fragment is attached to its host Activity.
       fragmentLoadTrace = FirebasePerformance.startTrace("TestFragment-LoadTime");
   }
  1. 注册FirstDrawListeneronViewCreated()回调。然后,类似的活动例如,停止跟踪在onDrawingFinish()

测试片段.java

@Override
public void onViewCreated(@NonNull View mainView, Bundle savedInstanceState) {
   super.onViewCreated(mainView, savedInstanceState);

   // ...

   // TODO (3): Register the callback to listen for first frame rendering (see
   //  "OnFirstDrawCallback" in FirstDrawListener) and stop the trace when view drawing is
   //  finished.
   FirstDrawListener.registerFirstDrawListener(mainView, new FirstDrawListener.OnFirstDrawCallback() {

       @Override
       public void onDrawingStart() {
           // In practice you can also record this event separately
       }

       @Override
       public void onDrawingFinish() {
           // This is when the Fragment UI is completely drawn on the screen
           fragmentLoadTrace.stop();
       }
   });
  1. 重新运行应用程序。然后,过滤器“登录跟踪指标”的logcat的。点按LOAD FRAGMENT按钮,并查找日志如下所示:
I/FirebasePerformance: Logging trace metric: TestFragment-LoadTime (duration: XXXms)

🎉恭喜!您已成功测量 Fragment 的加载时间并将该数据报告给 Firebase 性能监控。我们稍后将在本 Codelab 的 Firebase 控制台中查看记录的指标。

7. 了解屏幕渲染以及什么是慢帧/冻结帧

UI 渲染是从您的应用程序生成框架并将其显示在屏幕上的行为。为了确保使用者与应用的互动光滑,你的应用程序应该渲染帧16ms的下实现每秒60帧(为什么60fps的? )。如果您的应用出现 UI 渲染缓慢的问题,那么系统将被迫跳帧,用户会感觉到您的应用出现卡顿现象。我们称之为JANK。

同样,冷冻帧是需要超过700毫秒更长的时间来渲染UI框架。这种延迟是一个问题,因为您的应用程序似乎卡住了,并且在渲染帧时几乎一整秒都没有响应用户输入。

8. 测量一个 Fragment 的慢帧/冻结帧

火力性能监控自动捕捉缓/冻结帧为活动(但只有当它是硬件加速)。但是,此功能目前不适用于 Fragment。一个片段的慢/冻结帧被定义为慢/冻结帧的之间的整个活动onFragmentAttached()onFragmentDetached()在该片段中的生命周期回调。

从以动机AppStateMonitor(负责记录屏幕痕迹的活动性能监控SDK的一部分),我们实施了ScreenTrace类(这是本程式码实验室源代码回购的一部分)。 ScreenTrace类可以挂在活动的FragmentManager的生命周期回调捕获慢/冻结帧。该类提供了两个公共 API:

  • recordScreenTrace()开始记录屏幕跟踪
  • sendScreenTrace()停止屏幕跟踪和武官的记录自定义指标登录总,速度慢,冻结帧计数

通过将这些自定义指标,对于片段屏幕迹线可以被处理的方式,丝网迹线相同的一个活动,并且可以与其他一起显示屏幕呈现迹线在火力地堡控制台的性能仪表板。

以下是为 Fragment 记录屏幕跟踪的方法:

  1. 初始化ScreenTrace在活动承载片段类。

主活动.java

// Declare the Fragment tag
private static final String FRAGMENT_TAG = TestFragment.class.getSimpleName();

// TODO (1): Declare the ScreenTrace variable.
private ScreenTrace screenTrace;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // TODO (2): Initialize the ScreenTrace variable.
    screenTrace = new ScreenTrace(this, FRAGMENT_TAG);

    // ...
}
  1. 当你加载你的片段,注册FragmentLifecycleCallbacks并覆盖onFragmentAttached()onFragmentDetached()回调。我们已经为您完成了这项工作。你需要开始录制画面痕迹onFragmentAttached()回调和停止录音onFragmentDetached()回调。

主活动.java

private final FragmentManager.FragmentLifecycleCallbacks fragmentLifecycleCallbacks =
       new FragmentManager.FragmentLifecycleCallbacks() {

           @Override
           public void onFragmentAttached(@NonNull FragmentManager fm, @NonNull Fragment f, @NonNull Context context) {
               super.onFragmentAttached(fm, f, context);

               // TODO (3): Start recording the screen traces as soon as the Fragment is
               //  attached to its host Activity.
               if (FRAGMENT_TAG.equals(f.getTag()) && screenTrace.isScreenTraceSupported()) {
                   screenTrace.recordScreenTrace();
               }
           }

           @Override
           public void onFragmentDetached(@NonNull FragmentManager fm, @NonNull Fragment f) {
               super.onFragmentDetached(fm, f);

               // TODO (4): Stop recording the screen traces as soon as the Fragment is
               //  detached from its host Activity.
               if (FRAGMENT_TAG.equals(f.getTag()) && screenTrace.isScreenTraceSupported()) {
                   screenTrace.sendScreenTrace();
               }

               // Unregister Fragment lifecycle callbacks after the Fragment is detached
               fm.unregisterFragmentLifecycleCallbacks(fragmentLifecycleCallbacks);
           }
       };
  1. 重新运行应用程序。然后,点按LOAD FRAGMENT按钮。等待几秒钟,然后单击back button下方的导航栏上。

过滤器“记录跟踪指标”的logcat的,然后寻找类似下面的日志:

I/FirebasePerformance: Logging trace metric: _st_MainActivity-TestFragment (duration: XXXms)

过滤logcat的以“FireperfViews”,然后寻找类似下面的日志:

D/FireperfViews: sendScreenTrace MainActivity-TestFragment, name: _st_MainActivity-TestFragment, total_frames: XX, slow_frames: XX, frozen_frames: XX

🎉恭喜!您已成功测量 Fragment 的慢速/冻结帧并将该数据报告给 Firebase 性能监控。我们稍后将在本 Codelab 中查看 Firebase 控制台中记录的指标。

9. 在 Firebase 控制台中检查指标

  1. 在 logcat 中,单击 Firebase 控制台 URL 以访问详细信息页面以进行跟踪。 ceb9d5ba51bb6e89.jpeg

另外,在火力地堡控制台,选择具有您的应用程序项目。在左边的面板中,找到发布暨监视器部分,然后单击性能

  • 在主仪表板选项卡,向下滚动到的痕迹表,然后单击自定义选项卡的痕迹。在这个表格中,你会看到我们先前添加的自定义代码的痕迹以及一些外的开箱的痕迹,如_app_start痕迹。
  • 寻找你的两个自定义代码的痕迹, TestActivity-LoadTimeTestFragment-LoadTime 。点击时间为一方,以查看收集的数据的详细信息。

a0d8455c5269a590.png

  1. 自定义代码跟踪的详细信息页面显示有关跟踪持续时间的信息(即测量的加载时间)。

5e92a307b7410d8b.png

  1. 您还可以查看自定义屏幕跟踪的性能数据。
  • 返回到主仪表板选项卡,向下滚动到的痕迹表,然后单击屏幕渲染选项卡。在这个表格中,你会看到我们先前添加的自定义屏幕痕迹加上任何超出现成屏幕的痕迹,如MainActivity痕迹。
  • 寻找你的自定义屏幕跟踪, MainActivity-TestFragment 。单击跟踪名称可查看慢速渲染和冻结帧的聚合数据。

ee7890c7e2c28740.png

10. 恭喜

恭喜!您已经使用 Firebase 性能监控成功测量了 Activity 和 Fragment 的加载时间和屏幕渲染性能!

你所完成的

下一步是什么

Firebase Performance 提供了除自定义跟踪之外的更多应用性能测量方法。它可以自动测量应用程序的启动时间,应用功能于前台,并应用功能于后台性能数据。这时候你要检查在这些指标火力地堡控制台

此外,火力地堡性能报价自动HTTP / S网络请求监视。有了它,您无需编写一行代码即可轻松检测网络请求。你可以尝试把从您的应用程序的一些网络请求,并找到在指标火力地堡控制台

奖金

现在你知道如何测量负载时的画面呈现您的活动性能/片段通过使用自定义代码的痕迹,你能探索我们的开源代码库,看看你是否可以捕捉这些指标开箱任何活动/片段那是应用程序的一部分吗?如果您愿意,请随时发送 PR :-)

11. 奖励学习

了解加载 Activity 期间发生的情况将有助于您更好地了解应用的性能特征。在前面的步骤中,我们在较高级别描述了加载 Activity 期间发生的情况,但下图更详细地描述了每个阶段。

cd61c1495fad7961.png