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

1.はじめに

最終更新日: 2021-03-11

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

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

Firebase Performance Monitoringは、これらのパフォーマンス指標をすぐに利用できませんか?

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

あなたが学ぶこと

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

必要なもの

  • Android Studio4.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プロジェクトをAndroidStudioにインポートします。おそらく、いくつかのコンパイルエラー、またはgoogle-services.jsonファイルの欠落に関する警告が表示されます。これは、このステップの次のセクションで修正します。

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

アプリをFirebaseに接続します

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

e791bed0999db1e0.png

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

42c498d28ead2b77.png

  1. Android Studioに戻り、アシスタントペインに、アプリがFirebaseに接続されていることの確認が表示されます。

dda8bdd9488167a0.png

アプリにパフォーマンスモニタリングを追加する

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

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

9b58145acc4be030.png

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

aa0d46fc944e0c0b.png

追加の手順として、「(オプション)デバッグログを有効にする」の手順に従って、デバッグログを有効にします。同じ手順は、公開ドキュメントでも利用できます。

3.アプリを実行します

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

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

410d8686b4f45c33.png

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

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

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

アクティビティの読み込みを理解する

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

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

c20d14b151549937.png

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

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

5.アクティビティの読み込み時間を測定します

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

  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. 2つのコールバックを持つFistDrawListenerの実装が含まれています: onDrawingStart()onDrawingFinish()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をフィルタリングします。 LOAD ACTIVITYボタンをタップして、以下のようなログを探します。
I/FirebasePerformance: Logging trace metric: TestActivity-LoadTime (duration: XXXms)

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

FirstDrawListenerの目的

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

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

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

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. FirstDrawListeneronViewCreated()コールバックに登録します。次に、アクティビティの例と同様に、 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をフィルタリングします。 [フラグメントのLOAD FRAGMENT ]ボタンをタップして、次のようなログを探します。
I/FirebasePerformance: Logging trace metric: TestFragment-LoadTime (duration: XXXms)

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

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

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

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

8.フラグメントの低速/凍結フレームを測定します

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

AppStateMonitorクラス( Activityの画面トレースの記録を担当するPerformance Monitoring SDKの一部)から動機を取得して、 AppStateMonitorクラス(このcodelabソースコードリポジトリの一部)を実装しScreenTraceた。 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. Fragmentをロードするときは、 FragmentLifecycleCallbacksに登録し、 onFragmentAttached()およびonFragmentDetached()コールバックをオーバーライドします。私たちはあなたのためにこれを行いました。 onFragmentAttached()コールバックで画面トレースの記録を開始し、 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)

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

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

🎉おめでとうございます!フラグメントのSlow / Frozenフレームを正常に測定し、そのデータをFirebase PerformanceMonitoringに報告しました。記録された指標は、このコードラボの後半でFirebaseコンソールに表示されます。

9.Firebaseコンソールで指標を確認します

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

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

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

a0d8455c5269a590.png

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

5e92a307b7410d8b.png

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

ee7890c7e2c28740.png

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

おめでとう! Firebase Performance Monitoringを使用して、アクティビティとフラグメントの読み込み時間と画面レンダリングのパフォーマンスを正常に測定しました。

あなたが成し遂げたこと

次は何ですか

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

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

ボーナス

カスタムコードトレースを使用してアクティビティ/フラグメントの読み込み時間と画面レンダリングパフォーマンスを測定する方法がわかったので、オープンソースのコードベースを調べて、アクティビティ/フラグメントのこれらのメトリックをすぐにキャプチャできるかどうかを確認できますか?それはアプリの一部ですか?よろしければPRを送ってください:-)

11.ボーナスラーニング

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

cd61c1495fad7961.png