Począwszy od Androida 3.0 (poziom interfejsu API 11) potok renderowania 2D na Androidzie obsługuje sprzęt
przyspieszenie, czyli wszystkie operacje rysowania wykonywane na
Obszar roboczy View
korzysta z GPU. Ze względu na zwiększoną ilość zasobów wymaganych do
akceleracja sprzętowa, aplikacja zużywa więcej pamięci RAM.
Akceleracja sprzętowa jest domyślnie włączona, jeśli docelowy poziom interfejsu API wynosi >=14, ale może też
być jawnie włączone. Jeśli Twoja aplikacja korzysta tylko z widoków standardowych
Drawable
, włączenie tej funkcji globalnie nie powinno spowodować niekorzystnego rysowania
efekty. Akceleracja sprzętowa nie jest jednak obsługiwana w przypadku wszystkich rysunków 2D.
operacji, jego włączenie może mieć wpływ na niektóre widoki niestandardowe lub wywołania rysowania. Problemy
zwykle ujawniają się jako niewidoczne elementy, wyjątki lub nieprawidłowo renderowane piksele. Do
Aby temu zaradzić, Android umożliwia włączanie i wyłączanie akceleracji sprzętowej
poziomów. Zobacz Sterowanie akceleracją sprzętową.
Jeśli Twoja aplikacja umożliwia rysowanie niestandardowe, przetestuj ją na rzeczywistych urządzeniach sprzętowych. z włączoną akceleracją sprzętową, by wykryć problemy. W sekcji Obsługa operacji rysowania opisano znane problemy z: oraz sposoby obejścia tego problemu.
Zobacz też OpenGL z interfejsami Framework API. i Renderscript
Steruj akceleracją sprzętową
Możesz sterować akceleracją sprzętową na tych poziomach:
- Zgłoszenie do programu
- Aktywność
- Okno
- Wyświetl
Poziom aplikacji
W pliku manifestu Androida dodaj ten atrybut do
<application>
, aby włączyć akcelerację sprzętową w całym
aplikacja:
<application android:hardwareAccelerated="true" ...>
Poziom aktywności
Jeśli po włączeniu akceleracji sprzętowej globalnie aplikacja nie działa prawidłowo,
ale może też kontrolować ją
w przypadku poszczególnych działań. Aby włączyć lub wyłączyć akcelerację sprzętową na stronie
poziomu aktywności, możesz użyć atrybutu android:hardwareAccelerated
do
<activity>
. Poniższy przykład umożliwia włączenie akceleracji sprzętowej w przypadku
całą aplikację, ale wyłącza ją w przypadku jednego działania:
<application android:hardwareAccelerated="true"> <activity ... /> <activity android:hardwareAccelerated="false" /> </application>
Poziom okna
Jeśli potrzebujesz bardziej szczegółowej kontroli, możesz włączyć akcelerację sprzętową z następującym kodem:
Kotlin
window.setFlags( WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED, WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED )
Java
getWindow().setFlags( WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED, WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
Uwaga: obecnie nie można wyłączyć akceleracji sprzętowej w na poziomie okna.
Poziom widoku
Możesz wyłączyć akcelerację sprzętową dla pojedynczego widoku danych w czasie działania za pomocą ten kod:
Kotlin
myView.setLayerType(View.LAYER_TYPE_SOFTWARE, null)
Java
myView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
Uwaga: obecnie nie można włączyć akceleracji sprzętowej w na poziomie widoku. Oprócz wyłączania akceleracji sprzętowej warstwy widoku danych mają też inne funkcje. Więcej informacji o ich użyciu znajdziesz w artykule Wyświetlanie warstw.
Jak określić, czy widok jest z akceleracją sprzętową
Czasami przydaje się dla aplikacji informacja, czy w danym momencie jest to sprzęt Przyspieszone, szczególnie w przypadku widoków niestandardowych. Jest to szczególnie przydatne, jeśli może wykonywać wiele rysunków niestandardowych i nie wszystkie operacje są poprawnie obsługiwane i potoku renderowania.
Istnieją dwa sposoby sprawdzenia, czy aplikacja ma akcelerację sprzętową:
View.isHardwareAccelerated()
za możliwość zwrotutrue
, jeśliView
jest podłączony do akceleracji sprzętowej okno.Canvas.isHardwareAccelerated()
zwraca wartośćtrue
, jeśliCanvas
ma akcelerację sprzętową
Jeśli musisz to zrobić w kodzie rysunku, użyj
Zamiast tego Canvas.isHardwareAccelerated()
View.isHardwareAccelerated()
, gdy to możliwe. Po wyświetleniu
jest podłączony do okna z akceleracją sprzętową, można go wciąż narysować
Obszar roboczy z przyspieszeniem. Dzieje się tak na przykład podczas rysowania widoku do mapy bitowej na potrzeby buforowania
w celach informacyjnych.
Modele rysunkowe na Androidzie
Po włączeniu akceleracji sprzętowej platforma Androida używa nowego modelu rysowania, korzysta z list wyświetlanych, by wyświetlać aplikację na ekranie. Aby w pełni zrozumieć i ich wpływie na aplikację, warto zrozumieć, jak Android generuje też widoki bez akceleracji sprzętowej. W sekcjach poniżej znajdziesz opis z oprogramowaniem i z akceleracją sprzętową.
Model rysowania oparty na oprogramowaniu
W modelu rysowania programowego widoki są rysowane w następujących 2 krokach:
- Unieważnij hierarchię
- Narysuj hierarchię
Gdy aplikacja musi zaktualizować część interfejsu użytkownika, wywołuje funkcję invalidate()
(lub jeden z jej wariantów) w dowolnym widoku, który uległ zmianie
treści. Komunikaty o unieważnieniu są przekazywane aż do samej hierarchii widoku, aż do obliczenia
zabrudzony obszar ekranu, który należy ponownie narysować. System Android
rysuje dowolny widok w hierarchii, który przecina obszar zanieczyszczony. Niestety,
ma dwie wady tego modelu rysowania:
- Po pierwsze, ten model wymaga wykonania dużej ilości kodu przy każdym przebiegu pobierania. Na przykład, jeśli
aplikacja wywołuje
invalidate()
po naciśnięciu przycisku i że znajduje się nad innym widokiem, system Android ponownie rysuje go, została zmieniona. - Drugim problemem jest to, że model rysowania może ukrywać błędy w aplikacji. Ponieważ
System Android ponownie rysuje widoki, gdy krzyżują się z brudnym regionem, czyli widoku, którego zawartość
mogą zostać zmienione, nawet jeśli element
invalidate()
nie został w ten sposób. W takiej sytuacji korzystasz z unieważnienia innego widoku danych, aby uzyskać jego prawidłowe działanie. To zachowanie może się zmieniać za każdym razem, gdy zmodyfikujesz aplikację. Z powodu ten element powinien zawsze wywoływać funkcjęinvalidate()
we własnym zakresie za każdym razem, gdy zmienisz dane lub stan, które mają wpływ na kod rysowania widoku.
Uwaga: widoki na Androida automatycznie wywołują invalidate()
po zmianie ich właściwości, np. tła.
koloru lub tekstu w elemencie TextView
.
Przyspieszenie sprzętowe modelu rysowania
System Android nadal używa interfejsów invalidate()
i draw()
do wysyłania żądań aktualizacji ekranu i renderowania widoków, ale obsługuje
i rysować w inny sposób. Zamiast od razu wykonywać polecenia rysowania, system Android
rejestruje je na listach wyświetlania, które zawierają dane wyjściowe hierarchii widoków
do rysunków. Kolejna optymalizacja polega na tym, że system Android musi tylko
wyświetlaj listy wyświetleń oznaczonych jako „zanieczyszczone” według atrybutu invalidate()
. Widoki, które nie zostały unieważnione, można ponownie wykorzystać, ponownie przesyłając
zapisanej listy wyświetlacza. Nowy model rysowania składa się z 3 etapów:
- Unieważnij hierarchię
- Rejestrowanie i aktualizowanie wyświetlanych list
- Rysuj listy wyświetlanych
W przypadku tego modelu nie możesz polegać na widoku przecinającym zanieczyszczony region, aby jego metoda draw()
została wykonana. Aby system Android zarejestrował
wyświetlić listę wyświetlanych elementów, musisz wywołać funkcję invalidate()
. Zapominam
powoduje, że widok wygląda tak samo nawet po zmianie.
Użycie list w sieci reklamowej również zwiększa wydajność animacji, ponieważ ustawienie określonych właściwości
np. alfa czy rotacja, nie wymaga unieważniania docelowego widoku
). Optymalizacja ta dotyczy również widoków z listami w sieci reklamowej (każdy widok, w którym
z akceleracją sprzętową). Załóżmy na przykład, że istnieje element LinearLayout
zawierający znak ListView
powyżej wiersza Button
. Wyświetlana lista dla „LinearLayout
” wygląda tak
to:
- DrawDisplayList(ListView)
- DrawDisplayList(przycisk)
Załóżmy, że chcesz zmienić przezroczystość elementu ListView
. Po
wywoływanie funkcji setAlpha(0.5f)
na elemencie: ListView
, wyświetla się teraz lista
zawiera to:
- SaveLayerAlpha(0,5)
- DrawDisplayList(ListView)
- Przywróć
- DrawDisplayList(przycisk)
Złożony kod rysowania ListView
nie został wykonany. Zamiast tego makro
system zaktualizował tylko listę wyświetlania, która jest dużo prostsza w użyciu LinearLayout
. W
aplikację bez włączonej akceleracji sprzętowej, kod rysowania listy oraz jej
element nadrzędny zostanie wykonany ponownie.
Obsługa operacji rysowania
Z akceleracją sprzętową potok renderowania 2D obsługuje najczęściej używane
Canvas
operacji rysowania oraz wielu rzadziej używanych operacji. Wszystkie
operacje rysowania, które służą do renderowania aplikacji wysyłanych z Androidem, domyślnych widżetów
i układy, oraz typowe zaawansowane efekty wizualne, takie jak odbicia i tekstury kafelkowe,
obsługiwane.
W tabeli poniżej opisano poziom obsługi różnych operacji na różnych poziomach interfejsu API:
Pierwszy obsługiwany poziom interfejsu API | ||||
Canvas | ||||
DrobitmapMesh() (tablica kolorów) | 18 | |||
DrawPicture() | 23 | |||
DrawPosText() | 16 | |||
DrawTextOnPath() | 16 | |||
DrawVertices() | 29 | |||
setDrawFilter() | 16 | |||
klipPath() | 18 | |||
klipRegion() | 18 | |||
klipRect(Region.Op.XOR) | 18 | |||
klipRect(Region.Op.Różnica) | 18 | |||
klipRect(Region.Op.ReverseDifference) | 18 | |||
klipRect() z obrotem/perspektywą | 18 | |||
Barwiony | ||||
setAntiAlias() (dla tekstu) | 18 | |||
setAntiAlias() (dla linii) | 16 | |||
setFilterBitmap() | 17 | |||
setLinearText() | ✗ | |||
setMaskFilter() | ✗ | |||
setPathEffect() (dla linii) | 28 | |||
setShadowLayer() (inne niż tekst) | 28 | |||
setStrokeCap() (dla linii) | 18 | |||
setStrokeCap() (dla punktów) | 19 | |||
setSubpixelText() | 28 | |||
Xfermode | ||||
PorterDuff.Mode.DARKEN (bufor ramki) | 28 | |||
PorterDuff.Mode.LIGHTEN (bufor ramki) | 28 | |||
PorterDuff.Mode.OVERLAY (bufor ramki) | 28 | |||
Efekt cieniowania | ||||
ComposeShader w ComposeShader | 28 | |||
Mechanizmy cieniowania tego samego typu w ComposeShader | 28 | |||
Lokalna macierz w ComposeShader | 18 |
Skalowanie obszaru roboczego
Najpierw stworzono z akceleracją sprzętową potok renderowania 2D, który obsługuje nieskalowane rysunki, przy czym niektóre operacje rysowania znacznie pogarszają jakość przy wyższych wartościach skali. Te są implementowane jako tekstury rysowane w skali 1.0, przekształcane przez GPU. Uruchamiam w interfejsie API na poziomie 28, wszystkie operacje rysowania mogą być skalowane bez problemów.
W tabeli poniżej pokazujemy, kiedy implementacja została zmieniona, by zapewnić prawidłową obsługę dużych rozmiarów:Operacja rysowania do skalowania | Pierwszy obsługiwany poziom interfejsu API |
DrawText() | 18 |
DrawPosText() | 28 |
DrawTextOnPath() | 28 |
Proste kształty* | 17 |
Złożone kształty* | 28 |
DrawPath() | 28 |
Warstwa cienia | 28 |
Uwaga: „Prosty” kształty to drawRect()
,
drawCircle()
, drawOval()
, drawRoundRect()
i
Polecenia drawArc()
(z useCenter=false) z atrybutem Paint, które nie ma
PathEffect i nie zawiera złączeń innych niż domyślne (przez setStrokeJoin()
/
setStrokeMiter()
). Inne wystąpienia tych poleceń rysowania należą do kategorii „Złożone”, cale
powyżej.
Jeśli w Twojej aplikacji występują jakiekolwiek z tych brakujących funkcji lub ograniczeń, możesz
wyłącz akcelerację sprzętową tylko dla części aplikacji, której dotyczy problem, przez wywołanie
setLayerType(View.LAYER_TYPE_SOFTWARE, null)
Dzięki temu możesz:
nadal korzystać z akceleracji sprzętowej w innych miejscach. Więcej informacji o tym, jak ją włączyć, znajdziesz w artykule Sterowanie akceleracją sprzętową.
i wyłączaj akcelerację sprzętową na różnych poziomach w swojej aplikacji.
Wyświetl warstwy
We wszystkich wersjach Androida wyświetlenia
mogły być renderowane w buforach poza ekranem,
z pamięci podręcznej rysunku widoku lub przy użyciu funkcji Canvas.saveLayer()
. Bufory poza ekranem (w tym warstwy) mają wiele zastosowań. Możesz ich użyć, aby uzyskać
działa szybciej podczas animowania złożonych widoków lub stosowania efektów kompozycji. Przykład:
możesz zastosować efekty zanikania za pomocą Canvas.saveLayer()
, aby tymczasowo renderować widok
w warstwę, a potem umieścić na ekranie z określonym współczynnikiem przezroczystości.
Począwszy od Androida 3.0 (poziom interfejsu API 11) będziesz mieć większą kontrolę nad tym, jak i kiedy używać warstw
za pomocą metody View.setLayerType()
. Ten interfejs API zajmuje 2 razy
parametr: typ warstwy, którego chcesz użyć, oraz opcjonalny element Paint
opisujący sposób złożenia warstwy. Parametru Paint
możesz użyć, aby zastosować filtry kolorów, specjalne tryby mieszania lub przezroczystość do
warstwę. Widok może korzystać z jednego z 3 typów warstw:
LAYER_TYPE_NONE
: widok jest renderowany normalnie i nie ma kopii zapasowej. przez bufor poza ekranem. Jest to jego ustawienie domyślne.LAYER_TYPE_HARDWARE
: widok jest renderowany w postaci sprzętowej. tekstury sprzętowej, jeśli aplikacja jest akcelerowana sprzętowo. Jeśli aplikacja nie jest sprzętowa z przyspieszoną, ten typ warstwy działa tak samo jakLAYER_TYPE_SOFTWARE
.LAYER_TYPE_SOFTWARE
: widok jest renderowany w postaci oprogramowania. bitmapy.
Typ używanej warstwy zależy od Twojego celu:
- Wydajność: używanie sprzętowego typu warstwy do renderowania widoku sprzętowego.
teksturę. Po wyrenderowaniu widoku w warstwę nie trzeba wykonywać jej kodu rysowania
dopóki widok nie wywoła
invalidate()
. Niektóre animacje, np. animacji alfa, można następnie zastosować bezpośrednio w warstwie. dla GPU. - Efekty wizualne: użyj typu warstwy sprzętowej lub programowej oraz
Paint
, aby zastosować do widoku specjalne sekwencje wizualne. Możesz na przykład: do rysowania czarno-białego widoku za pomocąColorMatrixColorFilter
. - Zgodność: użyj typu warstwy programowej, aby wymusić renderowanie widoku w i oprogramowaniu. Jeśli widok z akceleracją sprzętową (np. cały film aplikacja jest akredytowana sprzętowo), ma problemy z renderowaniem, to łatwy sposób wokół ograniczeń renderowania sprzętowego potoku.
Wyświetlanie warstw i animacji
Warstwy sprzętowe mogą generować szybsze i płynniejsze animacje, gdy aplikacja
jest wspomagany sprzętowo. Uruchomienie animacji z szybkością 60 klatek na sekundę nie zawsze jest możliwe, gdy
animowanie złożonych widoków, które wymagają wielu operacji rysowania. Możesz temu złagodzić, stosując:
za pomocą warstw sprzętowych,
aby renderować widok na teksturze sprzętowej. Tekstura sprzętowa
a potem używane do animowania widoku, eliminując potrzebę ciągłego ponownego
nadawania widoku obrazu.
podczas animacji. Widok nie jest ponownie rysowany, chyba że zmienisz
właściwości, które wywołuje invalidate()
, lub w przypadku ręcznego wywołania invalidate()
. Jeśli używasz animacji w języku:
w danej aplikacji i nie uzyskać pożądanych wyników, spróbuj włączyć warstwy sprzętowe
ani ich animowanych wyświetleń.
Jeśli widok jest oparty na warstwie sprzętowej, niektóre jego właściwości są obsługiwane jest skomponowana na ekranie. Ustawienie tych właściwości będzie skuteczne, ponieważ nie będzie wymagają, aby widok został unieważniony i użyty ponownie. Poniższa lista właściwości wpływa na sposób warstwa jest skomponowana. Wywołanie metody ustawiającej dla dowolnej z tych właściwości zapewnia optymalną unieważnienie docelowego widoku danych i usunięcie go z nich:
alpha
: zmienia przezroczystość warstwyx
,y
,translationX
,translationY
: Zmienia pozycję warstwyscaleX
,scaleY
: zmienia rozmiar warstwyrotation
,rotationX
,rotationY
: zmienia wartość orientacja warstwy w przestrzeni 3DpivotX
,pivotY
: zmienia źródło przekształceń warstwy
Właściwości te to nazwy używane do animowania widoku za pomocą obiektu ObjectAnimator
. Jeśli chcesz uzyskać dostęp do tych właściwości, wywołaj odpowiednie polecenie
lub seterem. Aby na przykład zmodyfikować właściwość w wersji alfa, wywołaj funkcję setAlpha()
. Fragment kodu poniżej pokazuje najskuteczniejszy sposób
aby obrócić widok w 3D wokół osi Y:
Kotlin
view.setLayerType(View.LAYER_TYPE_HARDWARE, null) ObjectAnimator.ofFloat(view, "rotationY", 180f).start()
Java
view.setLayerType(View.LAYER_TYPE_HARDWARE, null); ObjectAnimator.ofFloat(view, "rotationY", 180).start();
Warstwy sprzętowe zużywają pamięć wideo, dlatego zdecydowanie zalecamy ich włączenie tylko na czas trwania animacji, a potem wyłącz je po jej zakończeniu. Ty można to zrobić za pomocą detektorów animacji:
Kotlin
view.setLayerType(View.LAYER_TYPE_HARDWARE, null) ObjectAnimator.ofFloat(view, "rotationY", 180f).apply { addListener(object : AnimatorListenerAdapter() { override fun onAnimationEnd(animation: Animator) { view.setLayerType(View.LAYER_TYPE_NONE, null) } }) start() }
Java
view.setLayerType(View.LAYER_TYPE_HARDWARE, null); ObjectAnimator animator = ObjectAnimator.ofFloat(view, "rotationY", 180); animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { view.setLayerType(View.LAYER_TYPE_NONE, null); } }); animator.start();
Więcej informacji o animacji właściwości znajdziesz w artykule Animacja usługi.
Porady i wskazówki
Przejście na grafikę 2D z akceleracją sprzętową może natychmiast zwiększyć wydajność, ale należy zaprojektować Twoją aplikację pod kątem efektywnego korzystania z GPU, stosując się do tych wskazówek: zalecenia:
- Zmniejszanie liczby wyświetleń w aplikacji
- Im więcej widoków danych utworzy system, tym wolniej będzie. Dotyczy to oprogramowania potok renderowania. Zmniejszenie liczby wyświetleń to jeden z najprostszych sposobów na optymalizację interfejsu.
- Unikaj przeciągania
- Nie rysuj na sobie zbyt wielu warstw. Usuń wszystkie widoki, które są całkowicie przesłonięty innymi nieprzezroczystymi widokami. Jeśli chcesz nałożyć na siebie kilka przemieszanych warstw rozważ połączenie ich w jedną warstwę. Dobrą ogólną zasadą jest Sprzęt nie może rysować więcej niż 2,5 raza liczby pikseli na ekranie na klatkę. (przezroczyste piksele w bitmapie).
- Nie twórz obiektów renderowania w metodach rysowania
- Częstym błędem jest tworzenie nowego elementu
Paint
lub nowegoPath
przy każdym wywołaniu metody renderowania. Wymusza to czyszczenia pamięci kolektora, aby działał częściej oraz pomijał pamięć podręczną i optymalizacje sprzętowe potoku. - Nie zmieniaj kształtów zbyt często.
- Na przykład złożone kształty, ścieżki lub okręgi są renderowane przy użyciu masek tekstur. Co podczas tworzenia lub modyfikowania ścieżki, potok sprzętowy tworzy nową maskę, którą można drogie.
- Nie modyfikuj zbyt często map bitowych
- Po każdej zmianie zawartości bitmapy jest ona ponownie przesyłana jako tekstura GPU przy następnym rysowaniu.
- Zachowaj ostrożność podczas korzystania z wersji alfa
- Gdy ustawisz widok jako półprzezroczysty za pomocą
setAlpha()
,AlphaAnimation
, lubObjectAnimator
, to jest renderowana w buforze poza ekranem, co powoduje podwojenie wymaganego współczynnika wypełnienia. Przy stosowaniu kanału alfa przy bardzo dużych widokach warto ustawić typ warstwy naLAYER_TYPE_HARDWARE