Firebase Performance Monitoring を使用して読み込み時間と画面レンダリングを測定する

Firebase Performance Monitoring を使用して読み込み時間と画面レンダリングを測定する

この Codelab について

subject最終更新: 10月 31, 2022
account_circle作成者: Jeremy Jiang, Ramanpreet Singh Khinda

1. はじめに

最終更新日: 2021 年 3 月 11 日

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

ビューは Android アプリの要であり、ユーザー エクスペリエンスに直接影響を与えます。たとえば、アクティビティまたはフラグメントには、ユーザーが操作するビュー コンポーネントを保持する UI が含まれています。画面に UI が完全に描画されるまで、ユーザーは UI のコンテンツ全体を表示できません。画面の遅れやフリーズは、アプリでのユーザー操作に直接悪影響を及ぼし、ユーザー エクスペリエンスを低下させます。

Firebase Performance Monitoring には、これらのパフォーマンス指標が標準で用意されていないのですか?

Firebase Performance Monitoring では、アプリの起動時間(最初のアクティビティの読み込み時間のみ)や画面レンダリングのパフォーマンス(アクティビティのフレームの遅延やフリーズ、フラグメントのフレームの遅延やフリーズは除く)など、一部のパフォーマンス データが自動的にキャプチャされます。ただし、業界向けアプリには通常、多くのアクティビティではなく、1 つのアクティビティと複数のフラグメントがあります。また、多くのアプリでは、より複雑なユースケースのために独自のカスタム ビューを実装しています。そのため、アプリでカスタムコード トレースを計測して、アクティビティとフラグメントの両方の読み込み時間と画面レンダリングのパフォーマンスを測定する方法を理解することが重要です。この Codelab を簡単に拡張して、カスタム ビュー コンポーネントのパフォーマンスを測定できます。

ラボの内容

  • Firebase Performance Monitoring を Android アプリに追加する方法
  • アクティビティまたはフラグメントの読み込みについて
  • カスタム コード トレースをインストルメント化してアクティビティまたはフラグメントの読み込み時間を測定する方法
  • 画面レンダリングと遅い/フリーズしたフレームの概要
  • カスタムコード トレースに指標を設定して、画面の遅れやフリーズを記録する方法
  • 収集された指標を 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 ファイルがないことを示す警告が表示されたりすることがあります。この問題は、このステップの次のセクションで修正します。

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

アプリを Firebase に接続する

  1. [Android Studio]/[Help] > [Check for updates] に移動して、Android Studio と Firebase Assistant の最新版を使用していることを確認します。
  2. [Tools] > [Firebase] を選択して、[Assistant] ペインを開きます。

e791bed0999db1e0.png

  1. [Performance Monitoring] を選択してアプリに追加し、[Performance Monitoring を使ってみる] をクリックします。
  2. [Connect to Firebase] をクリックして Android プロジェクトを Firebase に接続します。(ブラウザで Firebase コンソールが開きます)
  3. Firebase コンソールで [プロジェクトを追加] をクリックし、Firebase プロジェクト名を入力します。(Firebase プロジェクトがすでにある場合は、その既存のプロジェクトを選択することもできます)。[続行] をクリックして利用規約に同意し、Firebase プロジェクトと新しい Firebase アプリを作成します。
  4. 次に、新しい Firebase アプリを Android Studio プロジェクトに接続するためのダイアログが表示されます。

42c498d28ead2b77.png

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

dda8bdd9488167a0.png

Performance Monitoring をアプリに追加する

Android Studio の [Assistant] ペインで、[Add Performance Monitoring to your app] をクリックします。

[変更を承認] ダイアログが表示されます。[変更を承認] をクリックすると、Android Studio がアプリを同期し、必要な依存関係がすべて追加されます。

9b58145acc4be030.png

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

aa0d46fc944e0c0b.png

追加の手順として、デバッグ ロギングを有効にするには、「(省略可)デバッグ ロギングを有効にする」の手順に沿って操作します。同じ手順は公開ドキュメントでも確認できます。

3. アプリを実行する

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

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

410d8686b4f45c33.png

この Codelab の次のステップでは、アクティビティまたはフラグメントの読み込み時間と画面レンダリングのパフォーマンスを測定する方法について説明します。

4. アクティビティまたはフラグメントの読み込みを理解する

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

アクティビティの読み込みについて

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

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

c20d14b151549937.png

フラグメントの読み込みについて

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

5. Activity の読み込み時間を測定する

最初のフレームの遅延はユーザー エクスペリエンスの低下を招く可能性があるため、ユーザーが経験している最初の読み込みの遅延の程度を把握することが重要です。カスタムコード トレースをインストルメント化して、この読み込み時間を測定できます。

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

TestActivity.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() の 2 つのコールバックが含まれています。FirstDrawListener とそのパフォーマンスに影響を与える要因について詳しくは、次のセクションをご覧ください)。アクティビティの onCreate() コールバックの最後に FirstDrawListener を登録します。onDrawingFinish() コールバックで viewLoadTrace を停止する必要があります。

TestActivity.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 を「Logging trace metric」でフィルタします。LOAD ACTIVITY ボタンをタップし、次のようなログを探します。
I/FirebasePerformance: Logging trace metric: TestActivity-LoadTime (duration: XXXms)

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

FirstDrawListener の目的

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

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

FirstDrawListener の完全なコードは、こちらの Codelab のソースコードで確認できます。

6. フラグメントの読み込み時間を測定する

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

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

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

TestFragment.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() でトレースを停止します。

TestFragment.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 を「Logging trace metric」でフィルタします。LOAD FRAGMENT ボタンをタップし、次のようなログを探します。
I/FirebasePerformance: Logging trace metric: TestFragment-LoadTime (duration: XXXms)

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

7. 画面レンダリングと遅い/フリーズしたフレームの概要

UI レンダリングとは、アプリからフレームを生成して画面に表示することです。ユーザーのアプリ操作をスムーズにするためには、16 ms 以内にフレームをレンダリングし、60 フレーム/秒を達成する必要があります(Why 60fps? の動画をご覧ください)。アプリの UI レンダリングが遅い場合、システムはフレームをスキップせざるを得ず、ユーザーはアプリの動作がスムーズでないと感じます。これをジャンクと呼びます。

同様に、フリーズしたフレームは、レンダリングに 700 ミリ秒より長くかかる UI フレームです。フレームがレンダリングされている間、アプリが停止しているように見え、ユーザー入力にほぼ 1 秒間反応しないため、この遅延は問題です。

8. フラグメントの遅いフレーム/フリーズしたフレームを測定する

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

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

  • recordScreenTrace(): 画面トレースの記録を開始します。
  • sendScreenTrace(): 画面トレースの記録を停止し、カスタム指標を添付して、合計フレーム数、遅いフレーム数、フリーズしたフレーム数をログに記録します。

これらのカスタム指標をアタッチすると、Fragment の画面トレースをアクティビティの画面トレースと同様に処理し、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 をクリックします。

Logging trace metric」で logcat をフィルタし、次のようなログを探します。

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

FireperfViews」で logcat をフィルタし、次のようなログを探します。

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

🎉 おめでとうございます。フラグメントの遅いフレーム/フリーズしたフレームを正常に測定し、そのデータを Firebase Performance Monitoring に報告しました。記録された指標は、この Codelab の後半で 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