Ladezeit und Bildschirmdarstellung mit Firebase Performance Monitoring messen

1. Einführung

Zuletzt aktualisiert: 11.03.2021

Warum müssen wir die Leistung von Aufrufen messen?

Views sind ein wichtiger Bestandteil von Android-Anwendungen, die sich direkt auf die Nutzerfreundlichkeit auswirken. Ihre Aktivität oder Ihr Fragment enthält beispielsweise die Benutzeroberfläche mit den View-Komponenten, mit denen Nutzer interagieren. Nutzer können den gesamten Inhalt der Benutzeroberfläche erst sehen, wenn er vollständig auf dem Bildschirm dargestellt wird. Langsame und eingefrorene Bildschirme beeinträchtigen die Interaktion der Nutzer mit Ihrer App direkt und führen zu einer schlechten User Experience.

Sind diese Leistungsmesswerte nicht standardmäßig in Firebase Performance Monitoring enthalten?

Bei Firebase Performance Monitoring werden einige Leistungsdaten automatisch erfasst, z. B. die Startzeit Ihrer App (d. h. die Ladezeit nur für die erste Aktivität) und die Leistung beim Rendern von Bildschirmen (d. h. langsame und eingefrorene Frames für Aktivitäten, aber nicht für Fragmente). Branchenspezifische Apps haben jedoch in der Regel nicht viele Aktivitäten, sondern eine Aktivität und mehrere Fragmente. Außerdem implementieren viele Apps in der Regel eigene benutzerdefinierte Ansichten für komplexere Anwendungsfälle. Daher ist es oft hilfreich, die Ladezeit und die Leistung beim Rendern von Bildschirmen sowohl für Aktivitäten als auch für Fragmente zu messen, indem Sie benutzerdefinierte Code-Traces in Ihrer App instrumentieren. Sie können dieses Codelab ganz einfach erweitern, um die Leistung von Custom View-Komponenten zu messen.

Lerninhalte

  • Firebase Performance Monitoring zu einer Android-App hinzufügen
  • Laden einer Aktivität oder eines Fragments
  • Benutzerdefinierte Code-Traces instrumentieren, um die Ladezeit einer Aktivität oder eines Fragments zu messen
  • Bildschirmrendering und langsame/eingefrorene Frames
  • Benutzerdefinierte Code-Traces mit Messwerten instrumentieren, um langsame/eingefrorene Bildschirme aufzuzeichnen
  • Erfasste Messwerte in der Firebase Console ansehen

Voraussetzungen

  • Android Studio ab Version 4.0
  • Ein Android-Gerät oder ‑Emulator
  • Java-Version 8 oder höher

2. Einrichtung

Code abrufen

Führen Sie die folgenden Befehle aus, um den Beispielcode für dieses Codelab zu klonen. Dadurch wird auf Ihrem Computer ein Ordner mit dem Namen codelab-measure-android-view-performance erstellt:

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

Wenn Sie Git nicht auf Ihrem Computer haben, können Sie den Code auch direkt von GitHub herunterladen.

Importieren Sie das measure-view-performance-start-Projekt in Android Studio. Wahrscheinlich werden einige Kompilierungsfehler oder eine Warnung zu einer fehlenden google-services.json-Datei angezeigt. Das korrigieren wir im nächsten Abschnitt dieses Schritts.

In diesem Codelab verwenden wir das Firebase Assistant-Plug-in, um unsere Android-App in einem Firebase-Projekt zu registrieren und die erforderlichen Firebase-Konfigurationsdateien, Plug-ins und Abhängigkeiten zu unserem Android-Projekt hinzuzufügen – alles in Android Studio!

App mit Firebase verbinden

  1. Rufen Sie Android Studio/Hilfe > Nach Updates suchen auf, um sicherzugehen, dass Sie die neuesten Versionen von Android Studio und des Firebase Assistant verwenden.
  2. Wählen Sie Tools > Firebase aus, um den Bereich Assistant zu öffnen.
    e791bed0999db1e0.png
  3. Wählen Sie Performance Monitoring aus, um es Ihrer App hinzuzufügen, und klicken Sie dann auf Performance Monitoring verwenden.
  4. Klicken Sie auf die Schaltfläche zum Erstellen eines neuen Projekts und geben Sie einen Projektnamen ein (z. B. Measure Performance Codelab).
  5. Klicken Sie auf Weiter.
  6. Lesen und akzeptieren Sie bei Aufforderung die Firebase-Nutzungsbedingungen und klicken Sie dann auf Weiter.
  7. (Optional) Aktivieren Sie die KI-Unterstützung in der Firebase Console (als „Gemini in Firebase“ bezeichnet).
  8. Für dieses Codelab benötigen Sie kein Google Analytics. Deaktivieren Sie daher die Google Analytics-Option.
  9. Als Nächstes sollte ein Dialogfeld angezeigt werden, in dem Sie Ihre neue Firebase-App mit Ihrem Android Studio-Projekt verknüpfen können.
    42c498d28ead2b77.png
  10. Zurück in Android Studio sollte im Bereich Assistant die Bestätigung angezeigt werden, dass Ihre App mit Firebase verbunden ist.
    dda8bdd9488167a0.png

Performance Monitoring in Ihre App einbinden

Klicken Sie in Android Studio im Bereich Assistant auf Add Performance Monitoring to your app (Performance Monitoring zu Ihrer App hinzufügen).

Es sollte ein Dialogfeld zum Übernehmen von Änderungen angezeigt werden. Danach sollte Android Studio Ihre App synchronisieren, um sicherzustellen, dass alle erforderlichen Abhängigkeiten hinzugefügt wurden.

9b58145acc4be030.png

Schließlich sollte im Bereich Assistant in Android Studio die Erfolgsmeldung angezeigt werden, dass alle Abhängigkeiten richtig eingerichtet sind.

aa0d46fc944e0c0b.png

Als zusätzlichen Schritt können Sie Debug-Logging aktivieren. Folgen Sie dazu der Anleitung im Schritt „(Optional) Debug-Logging aktivieren“. Dieselbe Anleitung ist auch in der öffentlichen Dokumentation verfügbar.

3. Anwendung ausführen

Wenn Sie Ihre App erfolgreich in das Performance Monitoring SDK eingebunden haben, sollte das Projekt jetzt kompiliert werden. Klicken Sie in Android Studio auf Run > Run 'app' (Ausführen > „App“ ausführen), um die App auf Ihrem verbundenen Android-Gerät oder Emulator zu erstellen und auszuführen.

Die App hat zwei Schaltflächen, über die Sie zu einer entsprechenden Aktivität und einem entsprechenden Fragment gelangen, wie hier zu sehen:

410d8686b4f45c33.png

In den folgenden Schritten dieses Codelabs erfahren Sie, wie Sie die Ladezeit und die Leistung beim Rendern des Bildschirms Ihrer Aktivität oder Ihres Fragments messen.

4. Laden einer Aktivität oder eines Fragments

In diesem Schritt erfahren wir, was das System beim Laden einer Aktivität oder eines Fragments tut.

Laden einer Aktivität

Die Ladezeit einer Aktivität ist der Zeitraum von der Erstellung des Aktivitätsobjekts bis zum vollständigen Rendern des ersten Frames auf dem Bildschirm. Dann sieht der Nutzer die vollständige Benutzeroberfläche der Aktivität zum ersten Mal. Um zu messen, ob Ihre App vollständig gerendert wurde, können Sie die Methode reportFullyDrawn() verwenden, um die verstrichene Zeit zwischen dem Start der App und der vollständigen Anzeige aller Ressourcen und Anzeigeverläufe zu messen.

Wenn Ihre App startActivity(Intent) aufruft, führt das System automatisch die folgenden Prozesse aus: Jeder Prozess dauert eine Weile. Das verlängert die Zeit zwischen der Erstellung der Aktivität und dem Zeitpunkt, zu dem der Nutzer die Benutzeroberfläche für die Aktivität auf seinem Bildschirm sieht.

c20d14b151549937.png

Laden eines Fragments

Ähnlich wie bei der Aktivität wird die Ladezeit für ein Fragment als der Zeitraum definiert, der beginnt, wenn das Fragment an seine Hostaktivität angehängt wird, und endet, wenn der erste Frame für die Fragmentansicht vollständig auf dem Bildschirm gezeichnet wird.

5. Ladezeit einer Aktivität messen

Verzögerungen beim ersten Frame können zu einer schlechten Nutzererfahrung führen. Daher ist es wichtig, zu wissen, wie lange die anfängliche Ladeverzögerung bei Ihren Nutzern ist. Sie können einen benutzerdefinierten Code-Trace instrumentieren, um diese Ladezeit zu messen:

  1. Starten Sie den benutzerdefinierten Code-Trace (mit dem Namen TestActivity-LoadTime) in der Activity-Klasse, sobald das Activity-Objekt erstellt wurde.

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. Überschreiben Sie den onCreate()-Callback und rufen Sie die Ansicht ab, die von der setContentView()-Methode hinzugefügt wurde.
@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. Wir haben eine Implementierung von FistDrawListener eingefügt, die zwei Callbacks hat: onDrawingStart() und onDrawingFinish() (weitere Informationen zu FirstDrawListener und Faktoren, die sich auf die Leistung auswirken können, finden Sie im nächsten Abschnitt). Registrieren Sie die FirstDrawListener am Ende des onCreate()-Callbacks der Aktivität. Sie sollten viewLoadTrace im onDrawingFinish()-Callback beenden.

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. Führen Sie die App noch einmal aus und filtern Sie den Logcat dann nach Logging trace metric. Tippen Sie auf die Schaltfläche LOAD ACTIVITY und suchen Sie nach Logs wie den folgenden:
I/FirebasePerformance: Logging trace metric: TestActivity-LoadTime (duration: XXXms)

🎉 Herzlichen Glückwunsch! Sie haben die Ladezeit einer Aktivität erfolgreich gemessen und die Daten an Firebase Performance Monitoring gesendet. Wir sehen uns den aufgezeichneten Messwert später in der Firebase Console an.

Zweck von FirstDrawListener

Im Abschnitt direkt darüber haben wir eine FirstDrawListener registriert. Mit FirstDrawListener wird gemessen, wann der erste Frame gezeichnet wurde.

Es implementiert ViewTreeObserver.OnDrawListener und überschreibt den onDraw()-Callback, der aufgerufen wird, wenn der View-Baum gezeichnet werden soll. Das Ergebnis wird dann umschlossen, um zwei Utility-Callbacks bereitzustellen: onDrawingStart() und onDrawingFinish().

Den vollständigen Code für FirstDrawListener finden Sie im Quellcode dieses Codelabs.

6. Ladezeit eines Fragments messen

Die Ladezeit eines Fragments wird ähnlich wie die einer Aktivität gemessen, es gibt jedoch einige geringfügige Unterschiede. Wir instrumentieren wieder einen benutzerdefinierten Code-Trace:

  1. Überschreiben Sie den onAttach()-Callback und starten Sie die Aufnahme Ihres fragmentLoadTrace. Wir nennen diesen Trace Test-Fragment-LoadTime.

Wie in einem früheren Schritt erläutert, kann das Fragment-Objekt jederzeit erstellt werden. Es wird jedoch erst aktiv, wenn es an seine Host-Aktivität angehängt wird.

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. Registrieren Sie FirstDrawListener im onViewCreated()-Callback. Beenden Sie dann den Trace im onDrawingFinish(), ähnlich wie im Beispiel für Aktivitäten.

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. Führen Sie die App noch einmal aus und filtern Sie den Logcat dann nach Logging trace metric. Tippen Sie auf die Schaltfläche LOAD FRAGMENT und suchen Sie nach Logs wie den folgenden:
I/FirebasePerformance: Logging trace metric: TestFragment-LoadTime (duration: XXXms)

🎉 Herzlichen Glückwunsch! Sie haben die Ladezeit eines Fragments erfolgreich gemessen und die Daten an Firebase Performance Monitoring gesendet. Wir sehen uns den aufgezeichneten Messwert später in der Firebase Console an.

7. Bildschirmrendering und langsame/eingefrorene Frames

Beim UI-Rendering wird ein Frame aus Ihrer App generiert und auf dem Bildschirm angezeigt. Damit die Interaktion eines Nutzers mit Ihrer App reibungslos abläuft, sollten Frames in weniger als 16 ms gerendert werden, um 60 Frames pro Sekunde zu erreichen ( Warum 60 fps?). Wenn die Benutzeroberfläche Ihrer App langsam gerendert wird, muss das System Frames überspringen. Der Nutzer nimmt dann Ruckeln in Ihrer App wahr. Das nennen wir Jank.

Eingefrorene Frames sind UI-Frames, deren Rendering länger als 700 ms dauert. Diese Verzögerung ist ein Problem, da Ihre App während des Renderns des Frames fast eine Sekunde lang nicht reagiert und Nutzer sie nicht bedienen können.

8. Langsame/eingefrorene Frames eines Fragments messen

Bei Firebase Performance Monitoring werden automatisch langsame/eingefrorene Frames für eine Aktivität erfasst (aber nur, wenn sie hardwarebeschleunigt ist). Diese Funktion ist derzeit jedoch nicht für Fragmente verfügbar. Die langsamen/eingefrorenen Frames eines Fragments werden als die langsamen/eingefrorenen Frames für die gesamte Aktivität zwischen den onFragmentAttached()- und onFragmentDetached()-Callbacks im Lebenszyklus des Fragments definiert.

Wir haben die Klasse ScreenTrace (die Teil des Quellcode-Repositorys für dieses Codelab ist) an die Klasse AppStateMonitor (die Teil des Performance Monitoring SDK ist und für die Aufzeichnung von Bildschirm-Traces für Activity zuständig ist) angelehnt. Die Klasse ScreenTrace kann mit dem Lebenszyklus-Callback FragmentManager der Aktivität verknüpft werden, um langsame/eingefrorene Frames zu erfassen. Diese Klasse bietet zwei öffentliche APIs:

  • recordScreenTrace(): Startet die Aufzeichnung eines Bildschirm-Traces.
  • sendScreenTrace(): Beendet die Aufzeichnung eines Screen-Traces und hängt benutzerdefinierte Messwerte an die Log-Gesamtzahl, die Anzahl der langsamen und die Anzahl der eingefrorenen Frames an.

Durch das Anhängen dieser benutzerdefinierten Messwerte können Bildschirm-Traces für Fragmente genauso wie Bildschirm-Traces für eine Aktivität verarbeitet und zusammen mit anderen Traces für das Rendern von Bildschirmen im Leistungsdashboard der Firebase Console angezeigt werden.

So protokollieren Sie Bildschirm-Traces für Ihr Fragment:

  1. Initialisieren Sie die Klasse ScreenTrace in der Aktivität, in der das Fragment gehostet wird.

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. Wenn Sie Ihr Fragment laden, registrieren Sie sich für FragmentLifecycleCallbacks und überschreiben Sie die onFragmentAttached()- und onFragmentDetached()-Callbacks. Das haben wir für Sie erledigt. Sie müssen die Aufzeichnung von Bildschirm-Traces im onFragmentAttached()-Callback starten und im onFragmentDetached()-Callback beenden.

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. Führen Sie die App noch einmal aus und tippen Sie dann auf die Schaltfläche LOAD FRAGMENT. Warten Sie einige Sekunden und klicken Sie dann in der unteren Navigationsleiste auf back button.

Filtern Sie den Logcat mit Logging trace metric und suchen Sie dann nach Logs wie unten:

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

Filtern Sie den Logcat mit FireperfViews und suchen Sie dann nach Logs wie unten:

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

🎉 Herzlichen Glückwunsch! Sie haben die Anzahl der langsamen/eingefrorenen Frames für ein Fragment erfolgreich gemessen und die Daten an Firebase Performance Monitoring gesendet. Die aufgezeichneten Messwerte sehen wir uns später in diesem Codelab in der Firebase Console an.

9. Messwerte in der Firebase Console ansehen

  1. Klicken Sie im Logcat auf die Firebase Console-URL, um die Detailseite für einen Trace aufzurufen. ceb9d5ba51bb6e89.jpeg

Alternativ können Sie in der Firebase Console das Projekt mit Ihrer App auswählen. Suchen Sie im linken Bereich nach dem Abschnitt Release & Monitor und klicken Sie dann auf Leistung.

  • Scrollen Sie auf dem Haupttab Dashboard nach unten zur Tabelle mit den Traces und klicken Sie dann auf den Tab Benutzerdefinierte Traces. In dieser Tabelle sehen Sie die benutzerdefinierten Code-Traces, die wir zuvor hinzugefügt haben, sowie einige Standard-Traces, z. B. den _app_start-Trace.
  • Suchen Sie nach Ihren beiden benutzerdefinierten Code-Traces TestActivity-LoadTime und TestFragment-LoadTime. Klicken Sie auf die Dauer für einen der beiden Einträge, um weitere Details zu den erhobenen Daten aufzurufen.

a0d8455c5269a590.png

  1. Auf der Detailseite für den benutzerdefinierten Code-Trace sehen Sie Informationen zur Dauer des Trace (d.h. zur gemessenen Ladezeit).

5e92a307b7410d8b.png

  1. Sie können sich auch die Leistungsdaten für Ihren benutzerdefinierten Screen-Trace ansehen.
  • Kehren Sie zum Tab Dashboard zurück, scrollen Sie nach unten zur Tabelle mit den Traces und klicken Sie dann auf den Tab Screen rendering (Bildschirmrendering). In dieser Tabelle sehen Sie die benutzerdefinierten Bildschirm-Traces, die wir zuvor hinzugefügt haben, sowie alle Standard-Bildschirm-Traces, z. B. den MainActivity-Trace.
  • Suchen Sie Ihren benutzerdefinierten Screen-Trace, MainActivity-TestFragment. Klicken Sie auf den Namen des Traces, um die aggregierten Daten für langsames Rendern und eingefrorene Frames aufzurufen.

ee7890c7e2c28740.png

10. Glückwunsch

Glückwunsch! Sie haben die Ladezeit und die Leistung beim Rendern von Bildschirmen einer Aktivität und eines Fragments mit Firebase Performance Monitoring gemessen.

Ihre Erfolge

Nächste Schritte

Firebase Performance bietet neben benutzerdefinierten Traces weitere Möglichkeiten zur Leistungsmessung Ihrer App. Sie erfasst automatisch Leistungsdaten zur App-Startzeit, zur App im Vordergrund und zur App im Hintergrund. Sehen Sie sich diese Messwerte jetzt in der Firebase Console an.

Außerdem bietet Firebase Performance automatische Überwachung von HTTP/S-Netzwerkanfragen. So können Sie Netzwerkanfragen ganz einfach instrumentieren, ohne eine einzige Codezeile schreiben zu müssen. Können Sie versuchen, einige Netzwerkanfragen von Ihrer App zu senden und die Messwerte in der Firebase Console zu suchen?

Bonus

Nachdem Sie nun wissen, wie Sie die Ladezeit und die Leistung beim Rendern von Bildschirmen Ihrer Aktivität/Ihres Fragments mithilfe von benutzerdefinierten Code-Traces messen können, können Sie sich unsere Open-Source-Codebasis ansehen, um herauszufinden, ob Sie diese Messwerte sofort für jede Aktivität/jedes Fragment erfassen können, die/das Teil der App ist. Wenn du möchtest, kannst du den PR gerne senden :-)

11. Bonus-Lerneinheiten

Wenn Sie wissen, was beim Laden einer Aktivität passiert, können Sie die Leistungsmerkmale Ihrer App besser nachvollziehen. In einem früheren Schritt haben wir auf hoher Ebene beschrieben, was beim Laden einer Aktivität passiert. Das folgende Diagramm beschreibt jede Phase jedoch viel detaillierter.

cd61c1495fad7961.png