Firebase Performance Monitoring でロード時間と画面レンダリングを測定する

1. はじめに

最終更新日: 2021-03-11

ビューのパフォーマンスを測定する必要があるのはなぜですか?

ビューは、ユーザー エクスペリエンスに直接影響を与える Android アプリケーションの重要な部分です。たとえば、アクティビティまたはフラグメントには、ユーザーが操作するビュー コンポーネントを保持する UI が含まれています。 UI が画面上に完全に描画されるまで、ユーザーは UI のコンテンツ全体を見ることができません。画面が遅くフリーズすると、ユーザーによるアプリの操作が直接妨げられ、ユーザー エクスペリエンスが低下します。

Firebase Performance Monitoring は、すぐに使えるこれらのパフォーマンス指標を提供するのではないでしょうか?

Firebase Performance Monitoring は、アプリの開始時間 (つまり、最初のアクティビティのみの読み込み時間) や画面レンダリングのパフォーマンス (つまり、アクティビティではなく、アクティビティでは遅いフレームやフリーズしたフレームなど) などの一部のパフォーマンス データをすぐに使用できる状態で自動的にキャプチャします。断片)。ただし、業界アプリには通常、多数のアクティビティはなく、1 つのアクティビティと複数のフラグメントがあります。また、多くのアプリは通常、より複雑なユースケースのために独自のカスタム ビューを実装しています。したがって、アプリにカスタム コード トレースをインストルメント化することで、アクティビティとフラグメントの両方の読み込み時間と画面レンダリングのパフォーマンスを測定する方法を理解すると役立つことがよくあります。このコードラボを簡単に拡張して、カスタム ビュー コンポーネントのパフォーマンスを測定できます。

学べること

  • Firebase Performance Monitoring を Android アプリに追加する方法
  • アクティビティまたはフラグメントのロードを理解する
  • カスタム コード トレースをインストルメント化してアクティビティまたはフラグメントの読み込み時間を測定する方法
  • 画面レンダリングとスロー/フリーズフレームとは何かについて理解する
  • メトリクスを使用してカスタム コード トレースをインストルメント化して、低速/フリーズ画面を記録する方法
  • Firebase コンソールで収集された指標を表示する方法

必要なもの

  • Android Studio 4.0以降
  • Android デバイス/エミュレータ
  • Java バージョン 8 以降

2. セットアップをする

コードを取得する

次のコマンドを実行して、このコードラボのサンプル コードのクローンを作成します。これにより、マシン上に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ファイルが見つからないことに関する警告が表示されたりするでしょう。このステップの次のセクションでこれを修正します。

このコードラボでは、 Firebase Assistantプラグインを使用して Android アプリを Firebase プロジェクトに登録し、必要な Firebase 構成ファイル、プラグイン、依存関係を Android プロジェクトに追加します。これらはすべて Android Studio 内から行います

アプリを Firebase に接続する

  1. Android Studio /ヘルプ>アップデートの確認に移動して、最新バージョンの Android Studio と Firebase Assistant を使用していることを確認します。
  2. [ツール] > [Firebase]を選択して、 [アシスタント]ペインを開きます。

e791bed0999db1e0.png

  1. アプリに追加するパフォーマンス監視を選択し、 [パフォーマンス監視を開始する]をクリックします。
  2. [Firebase に接続]をクリックして Android プロジェクトを Firebase に接続します(これにより、ブラウザで Firebase コンソールが開きます)
  3. Firebase コンソールで[プロジェクトの追加]をクリックし、Firebase プロジェクト名を入力します(すでに Firebase プロジェクトがある場合は、代わりにその既存のプロジェクトを選択できます)[続行]をクリックして規約に同意し、Firebase プロジェクトと新しい Firebase アプリを作成します。
  4. 次に、新しい Firebase アプリを Android Studio プロジェクトに接続するためのダイアログが表示されます。

42c498d28ead2b77.png

  1. Android Studio に戻ると、 [アシスタント]ペインに、アプリが Firebase に接続されていることを確認するメッセージが表示されます。

dda8bdd9488167a0.png

アプリにパフォーマンス監視を追加する

Android Studio の[アシスタント]ペインで、 [アプリにパフォーマンス監視を追加]をクリックします。

変更を受け入れるためのダイアログが表示されます。その後、Android Studio はアプリを同期して、必要な依存関係がすべて追加されていることを確認します。

9b58145acc4be030.png

最後に、Android Studio の[アシスタント]ペインに、すべての依存関係が正しく設定されたことを示す成功メッセージが表示されます。

aa0d46fc944e0c0b.png

追加の手順として、「(オプション)デバッグ ログを有効にする」の手順に従ってデバッグ ログを有効にします。同じ手順が公開ドキュメントにも記載されています。

3. アプリを実行する

アプリを Performance Monitoring SDK と正常に統合すると、プロジェクトがコンパイルされるはずです。 Android Studio で、 [実行] > [「アプリ」を実行]をクリックして、接続されている Android デバイス/エミュレータ上でアプリをビルドして実行します。

アプリには、次のように、対応するアクティビティとフラグメントに移動する 2 つのボタンがあります。

410d8686b4f45c33.png

このコードラボの次の手順では、アクティビティまたはフラグメントの読み込み時間と画面レンダリングのパフォーマンスを測定する方法を学習します。

4. アクティビティまたはフラグメントのロードを理解する

このステップでは、アクティビティまたはフラグメントのロード中にシステムが何を行っているかを学習します。

アクティビティの読み込みについて理解する

アクティビティの場合、読み込み時間は、アクティビティ オブジェクトが作成されてから最初のフレームが画面上に完全に描画されるまでの時間として定義されます (これは、ユーザーが最初にアクティビティの完全な UI を目にする時間になります)時間)。アプリが完全に描画されているかどうかを測定するには、 reportFullyDrawn()メソッドを使用して、アプリケーションの起動からすべてのリソースとビュー階層の表示が完了するまでの経過時間を測定します。

大まかに言うと、アプリがstartActivity(Intent)を呼び出すと、システムは次のプロセスを自動的に実行します。各プロセスが完了するまでに時間がかかるため、アクティビティの作成からユーザーが画面にアクティビティの UI を表示するまでの時間が長くなります。

c20d14b151549937.png

フラグメントのロードを理解する

アクティビティと同様に、フラグメントのロード時間は、フラグメントがホスト アクティビティにアタッチされてから、フラグメント ビューの最初のフレームが画面上に完全に描画されるまでの時間として定義されます。

5. アクティビティのロード時間を測定する

最初のフレームの遅延はユーザー エクスペリエンスの低下につながる可能性があるため、ユーザーがどの程度の初期読み込み遅延を経験しているかを理解することが重要です。カスタム コード トレースを計測して、この読み込み時間を測定できます。

  1. Activity オブジェクトが作成されたらすぐに、Activity クラスでカスタム コード トレース ( TestActivity-LoadTimeという名前) を開始します。

テストアクティビティ.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. onDrawingStart()onDrawingFinish()という 2 つのコールバックを持つFistDrawListenerの実装が組み込まれています ( FirstDrawListenerの詳細とそのパフォーマンスに影響する可能性があるものについては、以下の次のセクションを参照してください) 。 Activity のonCreate()コールバックの最後にFirstDrawListenerを登録します。 onDrawingFinish()コールバックでviewLoadTrace停止する必要があります。

テストアクティビティ.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)

🎉おめでとうございます!アクティビティの読み込み時間を正常に測定し、そのデータを Firebase Performance Monitoring に報告しました。このコードラボの後半では、記録されたメトリクスを Firebase コンソールで確認します。

FirstDrawListener の目的

直前のセクションでは、 FirstDrawListenerを登録しました。 FirstDrawListenerの目的は、最初のフレームの描画がいつ開始され、いつ終了したかを測定することです。

これはViewTreeObserver.OnDrawListenerを実装し、View ツリーが描画される直前に呼び出されるonDraw()コールバックをオーバーライドします。次に、結果をラップして 2 つのユーティリティ コールバックonDrawingStart()およびonDrawingFinish()を提供します。

FirstDrawListenerの完全なコードは、このコードラボのソース コードにあります。

6. フラグメントのロード時間を測定する

フラグメントのロード時間の測定はアクティビティの測定方法と似ていますが、若干の違いがあります。もう一度、カスタム コード トレースをインストルメント化します。

  1. onAttach()コールバックをオーバーライドして、 fragmentLoadTraceの記録を開始します。このトレースにTest-Fragment-LoadTimeという名前を付けます。

前の手順で説明したように、Fragment オブジェクトはいつでも作成できますが、アクティブになるのはホスト アクティビティにアタッチされている場合のみです。

テストフラグメント.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. onViewCreated()コールバックにFirstDrawListenerを登録します。次に、アクティビティの例と同様に、 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)

🎉おめでとうございます!フラグメントの読み込み時間を正常に測定し、そのデータを Firebase Performance Monitoring に報告しました。このコードラボの後半では、記録されたメトリクスを Firebase コンソールで確認します。

7. 画面レンダリングとスロー/フリーズフレームとは何かについて理解する

UI レンダリングは、アプリからフレームを生成し、画面に表示する行為です。ユーザーとアプリの操作がスムーズになるように、アプリは 16 ミリ秒未満でフレームをレンダリングし、1 秒あたり 60 フレームを達成する必要があります (なぜ 60fps なのでしょうか? )。アプリの UI レンダリングが遅い場合、システムは強制的にフレームをスキップし、ユーザーはアプリの途切れを認識することになります。これをジャンクと呼びます。

同様に、フリーズしたフレームは、レンダリングに 700 ミリ秒以上かかる UI フレームです。アプリがスタックしているように見え、フレームのレンダリング中にほぼ 1 秒間ユーザー入力に応答しないため、この遅延が問題になります。

8. フラグメントのスロー/フリーズフレームを測定する

Firebase Performance Monitoring は、アクティビティの遅い/フリーズしたフレームを自動的にキャプチャします(ただし、ハードウェア アクセラレーションを使用している場合のみ)。ただし、この機能は現在フラグメントでは利用できません。フラグメントの低速/フリーズ フレームは、フラグメントのライフサイクルのonFragmentAttached()onFragmentDetached()コールバックの間のアクティビティ全体の低速/フリーズ フレームとして定義されます。

AppStateMonitorクラス ( Activity の画面トレースの記録を担当する Performance Monitoring SDK の一部) から動機を得て、 ScreenTraceクラス (この Codelab ソース コード リポジトリの一部) を実装しました。 ScreenTraceクラスをアクティビティのFragmentManagerのライフサイクル コールバックに接続して、低速/フリーズしたフレームをキャプチャできます。このクラスは、次の 2 つのパブリック API を提供します。

  • recordScreenTrace() : 画面トレースの記録を開始します
  • sendScreenTrace() : 画面トレースの記録を停止し、総フレーム数、低速フレーム数、およびフリーズ フレーム数をログに記録するカスタム メトリクスを添付します。

これらのカスタム指標をアタッチすると、フラグメントの画面トレースをアクティビティの画面トレースと同じ方法で処理でき、Firebase コンソールのパフォーマンスダッシュボードに他の画面レンダリング トレースと一緒に表示できます。

フラグメントの画面トレースをログに記録する方法は次のとおりです。

  1. フラグメントをホストするアクティビティでScreenTraceクラスを初期化します。

MainActivity.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()コールバックで記録を停止する必要があります。

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

🎉おめでとうございます!フラグメントの低速/フリーズ フレームを正常に測定し、そのデータを Firebase Performance Monitoring に報告しました。このコードラボの後半では、記録されたメトリクスを Firebase コンソールで確認します。

9. Firebase コンソールでメトリクスを確認する

  1. logcat で、Firebase コンソールの URL をクリックして、トレースの詳細ページにアクセスします。 ceb9d5ba51bb6e89.jpeg

あるいは、 Firebase コンソールで、アプリが含まれるプロジェクトを選択します。左側のパネルで、 「リリースと監視」セクションを見つけて、 「パフォーマンス」をクリックします。

  • メインの[ダッシュボード]タブで、トレース テーブルまで下にスクロールし、 [カスタム トレース]タブをクリックします。この表には、前に追加したカスタム コード トレースに加えて、 _app_startトレースなどのいくつかのすぐに使用できるトレースが表示されます。
  • 2 つのカスタム コード トレースTestActivity-LoadTimeTestFragment-LoadTimeを見つけます。いずれかの期間をクリックすると、収集されたデータの詳細が表示されます。

a0d8455c5269a590.png

  1. カスタム コード トレースの詳細ページには、トレースの継続時間 (つまり、測定されたロード時間) に関する情報が表示されます。

5e92a307b7410d8b.png

  1. カスタム画面トレースのパフォーマンス データを表示することもできます。
  • メインの[ダッシュボード]タブに戻り、トレース テーブルまで下にスクロールして、 [画面レンダリング]タブをクリックします。この表には、前に追加したカスタム画面トレースに加えて、 MainActivityトレースなどのすぐに使える画面トレースが表示されます。
  • カスタム画面トレースMainActivity-TestFragmentを見つけます。トレース名をクリックすると、レンダリングが遅いフレームとフリーズしたフレームの集計データが表示されます。

ee7890c7e2c28740.png

10. おめでとうございます

おめでとう! Firebase Performance Monitoring を使用して、アクティビティとフラグメントのロード時間と画面レンダリングのパフォーマンスを測定することに成功しました。

あなたが達成したこと

次は何ですか

Firebase Performance では、カスタム トレース以外にもアプリのパフォーマンスを測定するさまざまな方法が提供されます。アプリの起動時間、フォアグラウンドのアプリ、およびバックグラウンドのアプリのパフォーマンス データを自動的に測定します。 Firebase コンソールでこれらの指標を確認してみましょう。

また、Firebase Performance は、自動 HTTP/S ネットワーク リクエスト モニタリングを提供します。これにより、コードを 1 行も記述することなく、ネットワーク リクエストを簡単に計測できます。アプリからいくつかのネットワーク リクエストを送信してみて、 Firebase コンソールで指標を見つけていただけますか?

ボーナス

カスタム コード トレースを使用してアクティビティ/フラグメントのロード時間と画面レンダリング パフォーマンスを測定する方法がわかったので、オープンソースのコード ベースを調べて、任意のアクティビティ/フラグメントについてすぐにそれらのメトリクスを取得できるかどうかを確認してください。それはアプリの一部ですか?ご希望の場合は、お気軽に PR を送信してください:-)

11. ボーナス学習

アクティビティの読み込み中に何が起こっているかを理解することは、アプリのパフォーマンス特性をより深く理解するのに役立ちます。前のステップでは、アクティビティの読み込み中に何が起こるかを概要レベルで説明しましたが、次の図は各フェーズをより詳細に説明しています。

cd61c1495fad7961.png