Mierz czas wczytywania i renderowanie ekranu za pomocą Monitorowania wydajności Firebase

1. Wprowadzenie

Ostatnia aktualizacja: 2021-03-11

Dlaczego musimy mierzyć wydajność widoków?

Widoki są kluczowym elementem aplikacji na Androida, który bezpośrednio wpływa na wygodę użytkowników. Na przykład aktywność lub fragment zawiera interfejs, który zawiera komponenty widoku, z którymi użytkownicy wchodzą w interakcję. Użytkownicy nie widzą całej zawartości interfejsu, dopóki nie zostanie ona w pełni wyświetlona na ekranie. Powolne i zawieszające się ekrany bezpośrednio utrudniają interakcję użytkowników z aplikacją i pogarszają ich wrażenia.

Czy Monitorowanie wydajności Firebase nie udostępnia tych danych wydajności od razu?

Monitorowanie wydajności Firebase automatycznie rejestruje niektóre dane o wydajności, takie jak czas uruchamiania aplikacji (czyli czas wczytywania tylko pierwszej aktywności) i wydajność renderowania ekranu (czyli powolne i zamrożone klatki w przypadku aktywności, ale nie fragmentów). Aplikacje branżowe zwykle nie mają wielu aktywności, ale jedną aktywność i wiele fragmentów. W przypadku bardziej złożonych zastosowań wiele aplikacji implementuje też własne widoki niestandardowe. Dlatego często warto wiedzieć, jak mierzyć czas wczytywania i wydajność renderowania ekranu zarówno w przypadku aktywności, jak i fragmentów, poprzez instrumentowanie niestandardowych śladów kodu w aplikacji. Możesz łatwo rozszerzyć ten samouczek, aby mierzyć wydajność komponentów widoku niestandardowego.

Czego się nauczysz

  • Jak dodać Monitorowanie wydajności Firebase do aplikacji na Androida
  • Omówienie wczytywania aktywności lub fragmentu
  • Jak instrumentować niestandardowe ślady kodu, aby mierzyć czas wczytywania aktywności lub fragmentu
  • Renderowanie ekranu i powolne/zablokowane klatki
  • Jak instrumentować niestandardowe ślady kodu za pomocą danych, aby rejestrować powolne i zawieszone ekrany
  • Jak wyświetlać zebrane dane w konsoli Firebase

Czego potrzebujesz

  • Android Studio w wersji 4.0 lub nowszej.
  • urządzenie z Androidem lub emulator,
  • Java w wersji 8 lub nowszej

2. Przygotowanie

Pobierz kod

Aby sklonować przykładowy kod do tego laboratorium, uruchom te polecenia: Spowoduje to utworzenie na komputerze folderu o nazwie codelab-measure-android-view-performance:

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

Jeśli nie masz na komputerze narzędzia git, możesz też pobrać kod bezpośrednio z GitHub.

Zaimportuj projekt measure-view-performance-start do Android Studio. Prawdopodobnie zobaczysz błędy kompilacji lub ostrzeżenie o braku pliku google-services.json. Poprawimy to w następnej sekcji tego kroku.

W tym laboratorium kodowania użyjemy wtyczki Asystent Firebase, aby zarejestrować naszą aplikację na Androida w projekcie w Firebase i dodać do projektu aplikacji na Androida niezbędne pliki konfiguracyjne, wtyczki i zależności Firebase – wszystko w Android Studio.

Łączenie aplikacji z Firebase

  1. Aby mieć pewność, że używasz najnowszych wersji Android Studio i funkcji Firebase Assistant, otwórz Android Studio/Pomoc > Sprawdź aktualizacje.
  2. Kliknij Narzędzia > Firebase, aby otworzyć panel Asystent.
    e791bed0999db1e0.png
  3. Wybierz Performance Monitoring, aby dodać tę usługę do aplikacji, a potem kliknij Rozpocznij korzystanie z Performance Monitoring.
  4. Kliknij przycisk, aby utworzyć nowy projekt, a następnie wpisz jego nazwę (np. Measure Performance Codelab).
  5. Kliknij Dalej.
  6. Po wyświetleniu monitu zapoznaj się z warunkami usługi Firebase i zaakceptuj je, a potem kliknij Dalej.
  7. (Opcjonalnie) Włącz w konsoli Firebase pomoc AI (nazywaną „Gemini w Firebase”).
  8. W tym samouczku nie potrzebujesz Google Analytics, więc wyłącz opcję Google Analytics.
  9. Następnie powinien pojawić się dialog z prośbą o połączenie nowej aplikacji Firebase z projektem Androida Studio.
    42c498d28ead2b77.png
  10. W panelu Asystent w Android Studio powinna się pojawić informacja potwierdzająca, że aplikacja jest połączona z Firebase.
    dda8bdd9488167a0.png

Dodawanie monitorowania wydajności do aplikacji

W panelu Asystent w Android Studio kliknij Dodaj do aplikacji monitorowanie wydajności.

Powinno pojawić się okno dialogowe z prośbą o zaakceptowanie zmian. Po jego zamknięciu Android Studio zsynchronizuje aplikację, aby upewnić się, że dodano wszystkie niezbędne zależności.

9b58145acc4be030.png

Na koniec w panelu Asystent w Android Studio powinien pojawić się komunikat o powodzeniu operacji, informujący, że wszystkie zależności zostały skonfigurowane prawidłowo.

aa0d46fc944e0c0b.png

Dodatkowo włącz rejestrowanie debugowania, postępując zgodnie z instrukcjami w sekcji „(Opcjonalnie) Włącz rejestrowanie debugowania”. Te same instrukcje są też dostępne w dokumentacji publicznej.

3. Uruchamianie aplikacji

Jeśli udało Ci się zintegrować aplikację z pakietem SDK Performance Monitoring, projekt powinien się teraz skompilować. W Android Studio kliknij Uruchom > Uruchom „aplikację”, aby skompilować i uruchomić aplikację na podłączonym urządzeniu z Androidem lub emulatorze.

Aplikacja ma 2 przyciski, które przenoszą użytkownika do odpowiedniego komponentu Activity i fragmentu, np. tak:

410d8686b4f45c33.png

W kolejnych krokach tego modułu Codelabs dowiesz się, jak mierzyć czas wczytywania i wydajność renderowania ekranu w przypadku aktywności lub fragmentu.

4. Omówienie wczytywania aktywności lub fragmentu

W tym kroku dowiesz się, co system robi podczas wczytywania aktywności lub fragmentu.

Informacje o wczytywaniu aktywności

W przypadku aktywności czas wczytywania jest definiowany jako czas od utworzenia obiektu aktywności do momentu, w którym pierwsza ramka zostanie w całości narysowana na ekranie (wtedy użytkownik po raz pierwszy zobaczy pełny interfejs aktywności). Aby zmierzyć, czy aplikacja jest w pełni narysowana, możesz użyć metody reportFullyDrawn(), która mierzy czas, jaki upłynął od uruchomienia aplikacji do pełnego wyświetlenia wszystkich zasobów i hierarchii widoków.

Gdy aplikacja wywołuje funkcję startActivity(Intent), system automatycznie wykonuje te procesy: Każdy proces wymaga czasu, co wydłuża okres między utworzeniem aktywności a wyświetleniem interfejsu aktywności na ekranie użytkownika.

c20d14b151549937.png

Informacje o wczytywaniu fragmentu

Podobnie jak w przypadku aktywności, czas wczytywania fragmentu jest definiowany jako czas od momentu dołączenia fragmentu do aktywności hosta do momentu, w którym pierwsza klatka widoku fragmentu zostanie w pełni narysowana na ekranie.

5. Mierzenie czasu wczytywania aktywności

Opóźnienia w pierwszej klatce mogą negatywnie wpłynąć na wygodę użytkowników, dlatego ważne jest, aby wiedzieć, jak duże opóźnienie początkowego wczytywania występuje u użytkowników. Aby zmierzyć ten czas wczytywania, możesz instrumentować niestandardowe śledzenie kodu:

  1. Rozpocznij śledzenie kodu niestandardowego (o nazwie TestActivity-LoadTime) w klasie Activity od razu po utworzeniu obiektu Activity.

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. Zastąp wywołanie zwrotne onCreate() i uzyskaj widok dodany przez metodę 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. Wdrożyliśmy funkcję FistDrawListener, która ma 2 wywołania zwrotne: onDrawingStart()onDrawingFinish() (więcej informacji o FirstDrawListener i czynnikach, które mogą wpływać na jej skuteczność, znajdziesz w następnej sekcji). Zarejestruj FirstDrawListener na końcu wywołania zwrotnego onCreate()działania. Należy zatrzymać viewLoadTraceonDrawingFinish()wywołaniu zwrotnym.

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. Ponownie uruchom aplikację. Następnie przefiltruj logcat, używając ciągu „Logging trace metric” (Rejestrowanie danych śledzenia). Kliknij przycisk LOAD ACTIVITY i poszukaj logów podobnych do tych poniżej:
I/FirebasePerformance: Logging trace metric: TestActivity-LoadTime (duration: XXXms)

🎉 Gratulacje! Udało Ci się zmierzyć czas wczytywania aktywności i przesłać te dane do Monitorowania wydajności Firebase. W dalszej części tego laboratorium przyjrzymy się zarejestrowanym danym w konsoli Firebase.

Cel FirstDrawListener

W sekcji powyżej zarejestrowaliśmy znak FirstDrawListener. Celem FirstDrawListener jest pomiar czasu rozpoczęcia i zakończenia rysowania pierwszej klatki.

Implementuje interfejs ViewTreeObserver.OnDrawListener i zastępuje wywołanie zwrotne onDraw(), które jest wywoływane, gdy drzewo widoku ma zostać narysowane. Następnie opakowuje wynik, aby udostępnić 2 wywołania zwrotne narzędzia: onDrawingStart()onDrawingFinish().

Pełny kod FirstDrawListener znajdziesz w kodzie źródłowym tego ćwiczenia.

6. Pomiar czasu wczytywania fragmentu

Pomiar czasu wczytywania fragmentu jest podobny do pomiaru czasu wczytywania aktywności, ale z kilkoma drobnymi różnicami. Ponownie zinstrumentujemy niestandardowy ślad kodu:

  1. Zastąp onAttach() oddzwanianie i rozpocznij nagrywanie fragmentLoadTrace. Nazwiemy ten ślad Test-Fragment-LoadTime.

Jak wyjaśniliśmy w poprzednim kroku, obiekt Fragment można utworzyć w dowolnym momencie, ale staje się on aktywny dopiero po dołączeniu do aktywności hosta.

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. Zarejestruj FirstDrawListener w wywołaniu zwrotnym onViewCreated(). Następnie, podobnie jak w przypadku przykładu dotyczącego aktywności, zatrzymaj śledzenie w 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. Ponownie uruchom aplikację. Następnie przefiltruj logcat, używając ciągu „Logging trace metric” (Rejestrowanie danych śledzenia). Kliknij przycisk LOAD FRAGMENT i poszukaj logów podobnych do tych poniżej:
I/FirebasePerformance: Logging trace metric: TestFragment-LoadTime (duration: XXXms)

🎉 Gratulacje! Udało Ci się zmierzyć czas wczytywania fragmentu i przesłać te dane do Monitorowania wydajności Firebase. W dalszej części tego laboratorium przyjrzymy się zarejestrowanym danym w konsoli Firebase.

7. Wyjaśnienie renderowania ekranu i tego, czym jest powolna lub zablokowana klatka

Renderowanie interfejsu to generowanie klatki z aplikacji i wyświetlanie jej na ekranie. Aby interakcja użytkownika z aplikacją przebiegała płynnie, aplikacja powinna renderować klatki w czasie krótszym niż 16 ms, aby osiągnąć 60 klatek na sekundę ( dlaczego 60 klatek na sekundę?). Jeśli aplikacja ma problemy z szybkim renderowaniem interfejsu, system musi pomijać klatki, a użytkownik zauważy przeskoki w aplikacji. Nazywamy to zacięciem.

Podobnie zablokowane klatki to klatki interfejsu, których renderowanie trwa dłużej niż 700 ms. To opóźnienie jest problemem, ponieważ aplikacja wydaje się zawieszona i przez prawie sekundę nie reaguje na dane wejściowe użytkownika podczas renderowania klatki.

8. Pomiar spowolnionych i zablokowanych klatek fragmentu

Monitorowanie wydajności Firebase automatycznie rejestruje powolne lub zamrożone klatki w przypadku aktywności (ale tylko wtedy, gdy jest ona akcelerowana sprzętowo). Ta funkcja nie jest jednak obecnie dostępna w przypadku fragmentów. Spowolnione lub zamrożone klatki fragmentu to spowolnione lub zamrożone klatki całej aktywności między wywołaniami zwrotnymi onFragmentAttached()onFragmentDetached() w cyklu życia fragmentu.

Wzorując się na klasie AppStateMonitor (która jest częścią pakietu SDK do monitorowania wydajności odpowiedzialną za rejestrowanie śladów ekranu dla aktywności), zaimplementowaliśmy klasę ScreenTrace (która jest częścią tego repozytorium kodu źródłowego). Klasę ScreenTrace można połączyć z wywołaniem zwrotnym cyklu życia FragmentManager aktywności, aby rejestrować powolne lub zamrożone klatki. Ta klasa udostępnia 2 publiczne interfejsy API:

  • recordScreenTrace(): rozpoczyna nagrywanie śladu ekranu.
  • sendScreenTrace(): zatrzymuje nagrywanie śladu ekranu i dołącza niestandardowe dane pomiarowe do dziennika łącznej liczby klatek, liczby wolnych klatek i liczby zablokowanych klatek.

Dzięki dołączeniu tych niestandardowych danych ślady ekranu w przypadku fragmentów mogą być obsługiwane w taki sam sposób jak ślady ekranu w przypadku aktywności i mogą być wyświetlane wraz z innymi śladami renderowania ekranu na panelu Skuteczność w konsoli Firebase.

Aby rejestrować ślady ekranu w przypadku fragmentu:

  1. Zainicjuj klasę ScreenTrace w aktywności, która hostuje fragment.

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. Podczas wczytywania fragmentu zarejestruj wywołanie zwrotne FragmentLifecycleCallbacks i zastąp wywołania zwrotne onFragmentAttached() i onFragmentDetached(). Zrobiliśmy to za Ciebie. Musisz rozpocząć nagrywanie śladów ekranu w wywołaniu zwrotnym onFragmentAttached() i zatrzymać je w wywołaniu zwrotnym 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. Ponownie uruchom aplikację, a następnie kliknij przycisk LOAD FRAGMENT. Odczekaj kilka sekund, a potem kliknij back button na pasku nawigacyjnym u dołu.

Odfiltruj logcat za pomocą „Logging trace metric”, a potem poszukaj logów podobnych do tych poniżej:

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

Filtruj logcat za pomocą „FireperfViews”, a potem szukaj dzienników podobnych do tych poniżej:

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

🎉 Gratulacje! Udało Ci się zmierzyć liczbę powolnych i zablokowanych klatek w fragmencie i przesłać te dane do Firebase Performance Monitoring. W dalszej części tego laboratorium kodowania wyświetlimy zarejestrowane dane w konsoli Firebase.

9. Sprawdzanie danych w konsoli Firebase

  1. W Logcat kliknij adres URL konsoli Firebase, aby otworzyć stronę z informacjami o śledzeniu. ceb9d5ba51bb6e89.jpeg

Możesz też w konsoli Firebase wybrać projekt, w którym znajduje się Twoja aplikacja. W panelu po lewej stronie znajdź sekcję Wdrażanie i monitorowanie, a następnie kliknij Skuteczność.

  • Na głównej karcie Panel przewiń w dół do tabeli śladów, a następnie kliknij kartę Ślady niestandardowe. W tej tabeli zobaczysz ślady kodu niestandardowego, które dodaliśmy wcześniej, oraz niektóre gotowe ślady, np. ślad _app_start.
  • Znajdź 2 ślady kodu niestandardowego: TestActivity-LoadTimeTestFragment-LoadTime. Kliknij Czas trwania w przypadku jednego z nich, aby wyświetlić więcej szczegółów o zebranych danych.

a0d8455c5269a590.png

  1. Strona szczegółów logu czasu kodu niestandardowego zawiera informacje o czasie trwania logu czasu (czyli zmierzonym czasie wczytywania).

5e92a307b7410d8b.png

  1. Możesz też wyświetlić dane o skuteczności niestandardowego śledzenia ekranu.
  • Wróć do głównej karty Panel, przewiń w dół do tabeli śladów, a następnie kliknij kartę Renderowanie ekranu. W tej tabeli zobaczysz dodane wcześniej niestandardowe ślady ekranu oraz gotowe ślady ekranu, takie jak ślad MainActivity.
  • Znajdź niestandardowy ślad ekranu MainActivity-TestFragment. Kliknij nazwę śladu, aby wyświetlić zagregowane dane dotyczące powolnego renderowania i zamrożonych klatek.

ee7890c7e2c28740.png

10. Gratulacje

Gratulacje! Udało Ci się zmierzyć czas wczytywania i wydajność renderowania ekranu w przypadku aktywności i fragmentu za pomocą usługi Firebase Performance Monitoring.

Co udało Ci się osiągnąć

Co dalej?

Firebase Performance udostępnia więcej sposobów pomiaru wydajności aplikacji niż śledzenie niestandardowe. Automatycznie mierzy czas uruchamiania aplikacji oraz dane o wydajności aplikacji działającej na pierwszym planie i w tle. Czas sprawdzić te dane w konsoli Firebase.

Usługa Firebase Performance oferuje też automatyczne monitorowanie żądań sieciowych HTTP/S. Dzięki temu możesz łatwo instrumentować żądania sieciowe bez pisania ani jednej linijki kodu. Czy możesz wysłać z aplikacji kilka żądań sieciowych i sprawdzić dane w konsoli Firebase?

Premia

Teraz, gdy wiesz już, jak mierzyć czas wczytywania i wydajność renderowania ekranu w przypadku aktywności lub fragmentu za pomocą niestandardowych śladów kodu, możesz zapoznać się z naszą bazą kodu open source, aby sprawdzić, czy możesz rejestrować te dane od razu w przypadku dowolnej aktywności lub fragmentu, które są częścią aplikacji. Jeśli chcesz, możesz wysłać PR :-)

11. Dodatkowe materiały edukacyjne

Zrozumienie, co dzieje się podczas wczytywania aktywności, pomoże Ci lepiej poznać charakterystykę wydajności aplikacji. W poprzednim kroku opisaliśmy ogólnie, co dzieje się podczas wczytywania aktywności, ale poniższy diagram zawiera znacznie więcej szczegółów dotyczących każdej fazy.

cd61c1495fad7961.png