Wydajność i hierarchie widoków

Sposób zarządzania hierarchią View obiektu może mieć znaczny wpływ wydajność aplikacji. Na tej stronie dowiesz się, jak sprawdzić, czy hierarchia widoków spowalnia aplikacji i strategii rozwiązywania ewentualnych problemów.

Ta strona skupia się na ulepszaniu układów opartych na View. Informacje na temat ulepszania Wydajność Jetpack Compose: zobacz Jetpack Compose skuteczności reklam.

Układ i pomiar skuteczności

Potok renderowania obejmuje etap układu i pomiaru, na którym odpowiednio umieszcza odpowiednie elementy w hierarchii widoków. Część wskaźnika tego parametru etapie określa rozmiary i granice obiektów View. Element dotyczący układu określa, w którym miejscu na ekranie należy umieścić obiekty View.

Oba te etapy potoku wiążą się z niewielkim kosztem przetwarzanego widoku lub układu. Większość jest minimalny i nie wpływa znacząco na wydajność. Jednak może to być większe gdy aplikacja dodaje lub usuwa obiekty View, na przykład RecyclerView poddaje je recyklingowi lub jest używane ponownie. Koszt może też być wyższy, jeśli obiekt View wymaga do rozważenia zmiany rozmiaru, by sprostać jej ograniczeniom. Jeśli na przykład aplikacja wywołuje SetText() w obiekcie View, który zawija tekst, obiekt View może wymagać zmiany rozmiaru.

Jeśli taka sytuacja trwa zbyt długo, może to uniemożliwić wyrenderowanie klatki w dozwolonym 16 ms, co może powodować upuszczenie klatek i zakłócanie animacji.

Ponieważ nie możesz przenieść tych operacji do wątku instancji roboczej – aplikacja musi je przetworzyć w wątku głównym – najlepiej jest je zoptymalizować, aby zajmowały jak najmniej czasu.

Zarządzanie złożonymi układami

Układy Androida umożliwiają zagnieżdżanie obiektów UI hierarchii widoków. Takie zagnieżdżanie może też powodować naliczanie opłat za układ. Gdy aplikacja przetwarza obiekt w przypadku układu, aplikacja wykonuje ten sam proces na wszystkich jego elementach podrzędnych.

W przypadku skomplikowanego układu czasami koszt jest naliczany dopiero przy pierwszym obliczeniu przez system układ. Na przykład, gdy aplikacja odświeża złożony element listy w elemencie RecyclerView system musi rozmieścić wszystkie obiekty. Innym przykładem są banalne zmiany. jest rozpowszechniony w kierunku elementu nadrzędnego, aż dotrze do obiektu, który nie ma wpływu na rozmiar elementu nadrzędnego.

Częstą przyczyną długiego czasu wczytywania układu jest to, że hierarchie obiektów View są zagnieżdżone w innym miejscu. Każdy zagnieżdżony obiekt układu nalicza opłaty za etap układu. Lepszy tym mniej czasu zajmie ukończenie etapu układu.

Zalecamy użycie metody Edytora układów, by utworzyć ConstraintLayout, zamiast RelativeLayout lub LinearLayout, jak jest obecnie jest ogólnie bardziej efektywne i ogranicza zagnieżdżenie układów. Jednak w przypadku prostych układów, można osiągnąć za pomocą FrameLayout, zalecamy za pomocą: FrameLayout.

Jeśli używasz klasy RelativeLayout, możesz osiągnąć taki sam efekt niższym kosztem. Zamiast tego użyj zagnieżdżonych, nieważonych widoków LinearLayout. Pamiętaj jednak: jeśli używasz zagnieżdżonych, ważonych widoków LinearLayout, koszt układu jest znacznie wyższy ponieważ wymaga wielu kart układu, co wyjaśniono w następnej sekcji.

Zalecamy też używanie atrybutu RecyclerView zamiast atrybutu ListView, ponieważ może ona poddawać recyklingowi układy poszczególnych elementów listy, co zwiększa wydajność i może usprawnić przewijanie. skuteczność reklam.

Podwójne opodatkowanie

Zwykle platforma wykonuje etap układu lub pomiaru w jednym przejściu. Jednak w skomplikowanych przypadkach układów, struktura może być zmuszona wielokrotnie hierarchii, w której przed ostatecznym umieszczeniem elementów wymagane jest rozwiązanie wielu kart. Mając wykonanie więcej niż jednej iteracji układu i pomiaru to tzw. podwójne i podatku.

Jeśli na przykład korzystasz z kontenera RelativeLayout, który umożliwia określenie pozycji View obiektów względem pozycji innych obiektów View, platforma wykonuje tę sekwencję:

  1. Przeprowadza zaliczenie układu i pomiaru, podczas którego platforma oblicza wartość każdego obiektu podrzędnego pozycji i rozmiaru reklamy w zależności od potrzeb danego dziecka.
  2. Wykorzystuje te dane, biorąc pod uwagę waga obiektów, do określenia właściwej pozycji powiązane wyświetlenia.
  3. Wykonuje drugie przejście układu, by zakończyć pozycji.
  4. Przechodzi do następnego etapu procesu renderowania.

Im więcej poziomów ma Twoja hierarchia widoku, tym większe ryzyko pogorszenia wydajności.

Jak już wspominaliśmy, pakiet ConstraintLayout jest ogólnie skuteczniejszy niż inne układy z wyjątkiem: FrameLayout. Jest mniej podatna na wiele kart układu, a eliminuje potrzebę zagnieżdżania układów.

Kontenery inne niż RelativeLayout również mogą zwiększyć podwójne opodatkowanie. Dla: przykład:

  • Widok LinearLayout może skutkować podwójnym zaliczeniem układu i wskaźnika, jeśli w poziomie. Podwójny karnet układu i pomiaru może wystąpić również w orientacji pionowej, jeśli dodaj measureWithLargestChild, W takim przypadku platforma może potrzebować drugiego etapu, by rozwiązać problemy z odpowiednimi rozmiarami obiektów.
  • GridLayout także umożliwia pozycjonowanie względne, ale normalnie pozwala uniknąć podwójnego opodatkowania przez wstępne przetwarzanie relacje pozycjonowane między wyświetleniami dzieci. Jeśli jednak układ korzysta z wag lub wypełnienia Gravity, to korzyść zostanie utracone wstępne przetwarzanie, a platforma może wymagać wykonania wielu kart, jeśli kontener ma status RelativeLayout.

Wiele kart z uwzględnieniem układu i pomiarów nie musi obciążać wydajności. Mogą jednak stają się uciążliwym problemem, jeśli trafią w niewłaściwe miejsce. Zachowaj ostrożność w sytuacjach, gdy jeden z następujących elementów warunki mają zastosowanie do Twojego kontenera:

  • Jest to główny element w hierarchii widoków.
  • Ma głęboką hierarchię widoków.
  • Jest wiele sytuacji, w których wypełnia on ekran, podobnie jak dzieci, ListView obiekt.

Diagnozuj problemy z hierarchią widoków

Wydajność układu to złożony problem, który obejmuje wiele aspektów. Poniższe narzędzia mogą Ci pomóc określać, gdzie występują wąskie gardła wydajności. Niektóre narzędzia podają mniej jednoznaczne informacje ale mogą też dać pomocne wskazówki.

Perfetto

Perfetto to narzędzie, które dostarcza danych o skuteczności. Śledzenie Androida możesz otworzyć w Perfetto Google Analytics.

Profil renderowania GPU

renderowanie GPU profilu urządzenia. narzędzie, dostępne na urządzeniach z Androidem 6.0 (poziom interfejsu API 23) lub nowszym, dostarcza konkretnych informacji o wąskich gardłach wydajności. To narzędzie pozwala sprawdzić, jak długo dla każdego z nich jest przeprowadzany ramki renderowania. Te dane mogą pomóc w diagnozowaniu problemów z wydajnością środowiska wykonawczego oraz określać, jakie problemy z układem i pomiarami trzeba rozwiązać.

W graficznym przedstawienie przechwytywanych danych funkcja renderowania GPU w profilu używa koloru niebieskim reprezentującym czas układu. Więcej informacji na temat korzystania z tego narzędzia znajdziesz na stronie Szybkość renderowania za pomocą GPU profilu.

Liszka

Narzędzie Lint w Android Studio może ułatwić zorientowanie się i zmniejszają wydajność w hierarchii widoków. Aby użyć tego narzędzia, wybierz kolejno opcje Analizuj > Sprawdź kod, co pokazano na ilustracji 1.

Rysunek 1. W Android Studio kliknij Zbadaj kod.

Informacje o różnych elementach układu pojawiają się w sekcji Android > Lint > Skuteczność. Aby wyświetlić więcej szczegółów, kliknij każdy element, aby go rozwinąć. Wyświetl więcej informacji w panelu na po prawej stronie ekranu. Ilustracja 2 przedstawia przykład rozwiniętej informacji.

Rysunek 2. Wyświetlanie informacji o konkretnych problemach w narzędziu Lint

W panelu po prawej stronie kliknięcie elementu spowoduje wyświetlenie związanych z nim problemów.

Aby dowiedzieć się więcej o konkretnych tematach i problemach w tej dziedzinie, zobacz Dokumentacja Lint.

Narzędzie do inspekcji układu

Narzędzie Inspektor układu w Android Studio zapewnia wizualna reprezentacja hierarchii widoków aplikacji. To dobry sposób na poruszanie się po hierarchii w aplikacji, stanowiąc wyraźną reprezentację łańcucha nadrzędnego danego widoku i sprawdzić układy tworzone przez aplikację.

Widoki wyświetlane przez inspektora układu pomagają też zidentyfikować problemy z wydajnością wynikające o podwójnym opodatkowaniu. Może też służyć do identyfikowania głębokich łańcuchów układów zagnieżdżonych lub obszarów układu z dużą liczbą zagnieżdżonych elementów podrzędnych, co może być źródłem kosztów wydajności. W W takich przypadkach etapy układu i pomiaru mogą być kosztowne i powodować problemy z wydajnością.

Więcej informacji znajdziesz w artykule Debugowanie układu w: z inspektora układu i weryfikacji układu.

Rozwiązywanie problemów z hierarchią widoków

Podstawowa koncepcja rozwiązywania problemów z wydajnością, które powstają w wyniku hierarchii widoków, może w praktyce może być trudny. Zapobieganie nakładaniu kar za wydajność przez hierarchie widoków uproszczenia hierarchii widoków i ograniczenia podwójnego opodatkowania. W tej sekcji omawiamy strategie za realizację tych celów.

Usuń zbędne układy zagnieżdżone

ConstraintLayout to biblioteka Jetpack z wieloma różnymi mechanizmami pozycjonowania widoków układ. Pozwala to ograniczyć potrzebę zagnieżdżenia jednej kamery ConstaintLayout i może pomóc w spłaszczeniu widoku. w hierarchii. Zazwyczaj łatwiej jest spłaszczyć hierarchie, używając funkcji ConstraintLayout w porównaniu do innych typów układów.

Deweloperzy często używają więcej zagnieżdżonych układów, niż jest to konieczne. Na przykład plik Kontener RelativeLayout może zawierać pojedynczy element podrzędny, który jest również RelativeLayout kontener. Takie zagnieżdżanie jest zbędne i zwiększa zbędny koszt hierarchię widoków. Program Lint może oznaczyć ten problem za Ciebie, co skróci czas debugowania.

Scal lub uwzględnij

Częstą przyczyną zbędnych układów zagnieżdżonych jest to, <include> . Układ wielokrotnego użytku możesz na przykład zdefiniować w ten sposób:

<LinearLayout>
    <!-- some stuff here -->
</LinearLayout>

Następnie możesz dodać tag <include>, aby dodać do elementu nadrzędnego poniższy element kontener:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/app_bg"
    android:gravity="center_horizontal">

    <include layout="@layout/titlebar"/>

    <TextView android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:text="@string/hello"
              android:padding="10dp" />

    ...

</LinearLayout>

Poprzedni układ obejmuje niepotrzebnie zagnieżdżony pierwszy układ w drugim.

<merge> może pomóc zapobiec temu problemowi. Więcej informacji o tym tagu znajdziesz tutaj: Użyj funkcji <merge> .

Wdróż tańszy układ

Być może nie uda Ci się dostosować istniejącego schematu układu, by nie zawierał zbędnych elementów układy. W niektórych przypadkach jedynym rozwiązaniem może być spłaszczenie hierarchii przez przejście na zupełnie innego typu układu.

Możesz na przykład zauważyć, że TableLayout udostępnia te same działa w bardziej złożonym układzie z wieloma zależnościami pozycjonowymi. Biblioteka Jetpack ConstraintLayout udostępnia podobne funkcje co RelativeLayout oraz oferuje więcej funkcji ułatwiających tworzenie aby układy były bardziej płaskie i wydajne.