1. Wprowadzenie
Ostatnia aktualizacja: 2021-03-11
Dlaczego musimy mierzyć skuteczność wyświetleń?
Widoki są kluczowym elementem aplikacji na Androida, który bezpośrednio wpływa na wrażenia użytkownika. Na przykład aktywność lub fragment zawiera interfejs, który obejmuje 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ą użytkownikom korzystanie z aplikacji i pogarszają ich wrażenia.
Czy Monitorowanie wydajności Firebase nie udostępnia tych danych o wydajności od razu?
Monitorowanie wydajności Firebase automatycznie rejestruje niektóre dane o wydajności, np. 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 logów czasu 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 dostosowywać logi czasu niestandardowego kodu, aby mierzyć czas wczytywania aktywności lub fragmentu
- Wyjaśnienie renderowania ekranu i tego, czym jest powolna lub zablokowana klatka
- Jak dodawać do śladów kodu niestandardowego dane, 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 lub emulator z Androidem,
- 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
. Naprawimy to w następnej sekcji tego kroku.
W tym laboratorium kodowania użyjemy wtyczki Asystent Firebase, aby zarejestrować aplikację na Androida w projekcie Firebase i dodać do projektu Android niezbędne pliki konfiguracyjne, wtyczki i zależności Firebase – wszystko w Android Studio.
Łączenie aplikacji z Firebase
- Aby mieć pewność, że używasz najnowszych wersji Android Studio i Asystenta Firebase, otwórz Android Studio/Pomoc > Sprawdź aktualizacje.
- Kliknij Narzędzia > Firebase, aby otworzyć panel Asystent.
- Wybierz Performance Monitoring, aby dodać tę usługę do aplikacji, a potem kliknij Rozpocznij korzystanie z Performance Monitoring.
- Kliknij przycisk, aby utworzyć nowy projekt, a następnie wpisz jego nazwę (np.
Measure Performance Codelab
). - Kliknij Dalej.
- Po wyświetleniu monitu przeczytaj i zaakceptuj warunki usługi Firebase, a potem kliknij Dalej.
- (Opcjonalnie) Włącz w konsoli Firebase pomoc AI (nazywaną „Gemini w Firebase”).
- W tym samouczku nie potrzebujesz Google Analytics, więc wyłącz opcję Google Analytics.
- Następnie powinien pojawić się dialog z prośbą o połączenie nowej aplikacji Firebase z projektem Android Studio.
- W panelu Asystent w Android Studio powinna się pojawić informacja potwierdzająca, że aplikacja jest połączona z Firebase.
Dodawanie monitorowania wydajności do aplikacji
W panelu Asystent w Android Studio kliknij Dodaj do aplikacji Performance Monitoring.
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.
Na koniec w panelu Asystent w Androidzie Studio powinien pojawić się komunikat o powodzeniu, informujący, że wszystkie zależności zostały prawidłowo skonfigurowane.
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 Run (Uruchom) > Run „app” (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 działania i fragmentu, np.:
W kolejnych krokach tego modułu 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 ładowania jest definiowany jako czas od utworzenia obiektu aktywności do momentu, w którym pierwsza ramka zostanie w pełni 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.
Omówienie wczytywania 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ć niestandardowy log czasu kodu:
- 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");
// ...
}
- 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);
// ...
}
- Wdrożyliśmy funkcję
FistDrawListener
, która ma 2 wywołania zwrotne:onDrawingStart()
ionDrawingFinish()
(więcej informacji oFirstDrawListener
i czynnikach, które mogą wpływać na jej skuteczność, znajdziesz w następnej sekcji). ZarejestrujFirstDrawListener
na końcu wywołania zwrotnegoonCreate()
działania. Należy zatrzymaćviewLoadTrace
wonDrawingFinish()
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();
}
});
- 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()
i 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 utworzymy ślad niestandardowego kodu:
- Zastąp
onAttach()
oddzwanianie i rozpocznij nagrywaniefragmentLoadTrace
. Nazwiemy ten śladTest-Fragment-LoadTime
.
Zgodnie z wyjaśnieniem 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");
}
- Zarejestruj
FirstDrawListener
w wywołaniu zwrotnymonViewCreated()
. Następnie, podobnie jak w przypadku przykładu dotyczącego aktywności, zatrzymaj śledzenie wonDrawingFinish()
.
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();
}
});
- 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 proces generowania klatki z aplikacji i wyświetlania 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 zacinanie się aplikacji. Nazywamy to zacinaniem.
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ę zawieszać i nie reaguje na działania użytkownika przez prawie sekundę 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 są definiowane jako spowolnione lub zamrożone klatki całej aktywności między wywołaniami zwrotnymi onFragmentAttached()
i 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
, 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 dane niestandardowe do dziennika łącznej liczby klatek, liczby wolnych klatek i liczby zamrożonych 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 Wydajność w konsoli Firebase.
Aby rejestrować ślady ekranu w przypadku fragmentu:
- 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);
// ...
}
- Podczas wczytywania fragmentu zarejestruj wywołanie zwrotne
FragmentLifecycleCallbacks
i zastąp wywołania zwrotneonFragmentAttached()
ionFragmentDetached()
. Zrobiliśmy to za Ciebie. Musisz rozpocząć nagrywanie śladów ekranu w wywołaniu zwrotnymonFragmentAttached()
i zatrzymać je w wywołaniu zwrotnymonFragmentDetached()
.
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);
}
};
- Uruchom ponownie aplikację, a następnie kliknij przycisk
LOAD FRAGMENT
. Odczekaj kilka sekund, a potem kliknijback 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
- W logcat kliknij adres URL konsoli Firebase, aby otworzyć stronę ze szczegółami śledzenia.
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-LoadTime
iTestFragment-LoadTime
. Kliknij Czas trwania w przypadku jednego z nich, aby wyświetlić więcej szczegółów o zebranych danych.
- Strona szczegółów logu czasu kodu niestandardowego zawiera informacje o czasie trwania logu czasu (czyli zmierzonym czasie wczytywania).
- 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, np. ślad
MainActivity
. - Znajdź niestandardowy ślad ekranu
MainActivity-TestFragment
. Kliknij nazwę śledzenia, aby wyświetlić zagregowane dane dotyczące powolnego renderowania i zamrożonych klatek.
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ąć
- Masz zintegrowane Monitorowanie wydajności Firebase z przykładową aplikacją.
- Znasz już cykl życia wczytywania widoku.
- Czas wczytywania aktywności i fragmentu został zmierzony przez dodanie niestandardowych logów czasu.
- Zarejestrowano powolne lub zamrożone klatki przez dodanie niestandardowych logów czasu ekranu z niestandardowymi danymi.
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 na pierwszym planie i w tle. Czas sprawdzić te dane w konsoli Firebase.
Monitorowanie wydajności Firebase oferuje też automatyczne monitorowanie żądań sieciowych HTTP/S. Dzięki temu możesz łatwo instrumentować żądania sieciowe bez pisania ani jednej linii 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 przejrzeć 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. Bonus Learning
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.