Jeśli nie będziesz uważać, praca z obrazami może szybko spowodować problemy z wydajnością. Nawet niewielka grafika w skompresowanym formacie, takim jak JPG lub PNG, może po zdekodowaniu do wyświetlenia zamienić się w dużą bitmapę. Jeśli nie będziesz efektywnie korzystać z grafiki, możesz napotkać problemy z pamięcią, które mogą pogorszyć wydajność Twojej aplikacji i innych aplikacji na urządzeniu. Postępuj zgodnie z tymi sprawdzonymi metodami, aby zapewnić optymalną wydajność aplikacji.
Korzystanie z bibliotek do wczytywania obrazów
Możesz zwiększyć wydajność aplikacji, korzystając z bibliotek do wczytywania obrazów takich jak Coil (w przypadku projektów Kotlin) lub Glide (w przypadku projektów Java). Biblioteki te zmniejszają wykorzystanie pamięci przez aplikację, m.in. dzięki buforowaniu obrazów, zmniejszaniu rozdzielczości grafiki w razie potrzeby i ponownemu wykorzystywaniu obiektów graficznych.
Zmniejszanie rozdzielczości obrazów
Upewnij się, że używasz obrazu o odpowiednim rozmiarze. Unikaj wczytywania dużego obrazu w wysokiej rozdzielczości do małego kontenera (np. miniatury). Zamiast tego użyj zmniejszania rozdzielczości, aby zmniejszyć obraz przed zdekodowaniem go do pamięci.
Zmniejszanie rozdzielczości po stronie klienta
Biblioteki do wczytywania obrazów, takie jak Coil i Glide, automatycznie zmniejszają rozdzielczość. Strategie zmniejszania rozdzielczości możesz skonfigurować
za pomocą ImageLoader (w przypadku biblioteki Coil) lub DownsampleStrategy
(w przypadku biblioteki Glide). Jeśli zarządzasz bitmapami ręcznie, możesz użyć
inSampleSize, aby zdekodować mniejszą wersję. Aby to zrobić bezpiecznie, należy
najpierw ustawić inJustDecodeBounds na true, aby odczytać wymiary obrazu
bez przydzielania pamięci, obliczyć rozmiar próbki, ustawić inSampleSize na
tę wartość, ustawić inJustDecodeBounds na false, a następnie zdekodować obraz.
Preferowanie zmiany rozmiaru po stronie serwera
W miarę możliwości wysyłaj żądania dotyczące dokładnych wymiarów obrazu bezpośrednio do serwera backendu. Zmniejsza to wykorzystanie sieci i rozmiar pamięci podręcznej dysku, a jednocześnie zapewnia mniejsze wykorzystanie pamięci, ponieważ nie trzeba zmieniać rozmiaru obrazów na urządzeniu.
Możesz skonfigurować biblioteki tak, aby dynamicznie dołączały rozmiar widoku docelowego do adresu URL obrazu. Na przykład biblioteka Coil umożliwia to za pomocą niestandardowych przechwytujących, a biblioteka Glide obsługuje to za pomocą niestandardowych modułów wczytywania modeli (np. BaseGlideUrlLoader).
Unikanie nieograniczonych rozmiarów układu
Aby moduły wczytywania obrazów mogły skutecznie zmniejszać rozdzielczość (po stronie klienta lub serwera), muszą znać rozmiar docelowy przed wykonaniem żądania.
Unikaj używania wrapContentSize lub pozostawiania wymiarów bez ograniczeń w przypadku elementów kompozycyjnych, które wczytują obrazy zdalne. Jeśli te biblioteki nie mogą określić granic docelowych, wczytują oryginalny obraz w pełnym rozmiarze.
Może to spowodować wczytanie znacznie większego obrazu niż jest to konieczne, co zwiększy wykorzystanie pamięci i opóźnienie.
Zamiast tego ustaw jawne wymiary w elemencie kompozycyjnym obrazu (np. za pomocą Modifier.size) lub zdefiniuj proporcje. Umożliwia to silnikowi układu obliczenie dokładnego rozmiaru docelowego w pikselach, którego moduł wczytywania obrazów może następnie użyć do wysłania żądania i zdekodowania zasobu o odpowiednim rozmiarze.
Dostarczanie zasobów alternatywnych dla różnych rozmiarów ekranu
Jeśli dostarczasz obrazy razem z aplikacją, rozważ udostępnienie zasobów o różnych rozmiarach dla różnych rozdzielczości urządzeń. Może to pomóc zmniejszyć rozmiar pobierania aplikacji na urządzeniach i poprawić wydajność, ponieważ na urządzeniu o niższej rozdzielczości będzie wczytywany obraz o niższej rozdzielczości. Więcej informacji o udostępnianiu alternatywnych bitmap dla różnych rozmiarów urządzeń znajdziesz w dokumentacji dotyczącej alternatywnych bitmap.
Nie stosuj bezpośrednio dopełnienia
Czasami może być konieczne dodanie dopełnienia do obrazu. Możesz na przykład chcieć, aby obraz był otoczony przezroczystym obramowaniem, aby uzyskać efekt letterbox.
W takich sytuacjach nie dodawaj dopełnienia bezpośrednio do obrazu, zmieniając
jego wymiary. Zamiast tego pozostaw wymiary obrazu bez zmian,
i dostosuj jego położenie na ekranie za pomocą InsetDrawable.
Możesz też dodać dopełnienie do elementu kompozycyjnego lub widoku zawierającego obraz.
Wybór odpowiedniego formatu pikseli
Wybierz odpowiedni format pikseli, aby zachować równowagę między pamięcią a jakością. Jeśli nie potrzebujesz przezroczystości, użyj formatu RGB_565. Zużywa on o połowę mniej pamięci niż domyślny format ARGB_8888.
W bibliotece Glide możesz skonfigurować to ustawienie za pomocą DecodeFormat. W bibliotece Coil możesz
użyć właściwości bitmapConfig.
W miarę możliwości używaj grafiki wektorowej
W przypadku obrazów składających się z kształtów geometrycznych grafika wektorowa jest znacznie mniejsza niż bitmapa i można ją płynnie skalować do dowolnej gęstości wyświetlania. W odpowiednich przypadkach używaj elementów
takich jak ShapeDrawable do przedstawiania grafiki.
W miarę możliwości zwalniaj i ponownie używaj bitmap
Duże pliki graficzne mogą zajmować dużo pamięci. Aby zmniejszyć ich wpływ, w miarę możliwości zwalniaj lub ponownie używaj obiektów graficznych.
Jeśli używasz biblioteki do wczytywania obrazów, pamiętaj, aby zwalniać bitmapy w zarządzanym przez bibliotekę puli, gdy nie są już potrzebne. Biblioteka może w razie potrzeby ponownie użyć obiektów i zachować bufor pamięci na przyszłość.
Jeśli zarządzasz grafiką ręcznie, po zakończeniu pracy z nią zwolnij
bitmapy, wywołując Bitmap.recycle
i natychmiast odrzucając odwołanie Bitmap, zamiast
polegać na odśmiecaniu pamięci.
Inne porady i wskazówki
W tej sekcji znajdziesz kilka innych sposobów na poprawę wydajności aplikacji podczas obsługi grafiki.
Nie dołączaj dużych obrazów do pliku AAB/APK
Jedną z głównych przyczyn dużego rozmiaru pobierania aplikacji jest grafika dołączona do pliku AAB lub APK. Użyj narzędzia do analizy APK, aby sprawdzić , czy nie dołączasz plików graficznych większych niż wymagane. Zmniejsz rozmiary lub rozważ umieszczenie obrazów na serwerze i pobieranie ich tylko wtedy, gdy są potrzebne.
Znajdowanie zbędnych bitmap
Jeśli masz kilka kopii tego samego obrazu, marnujesz pamięć. Za pomocą profilera Androida Studio możesz zidentyfikować zbędną grafikę. Użyj zrzutu sterty analizatora, aby utworzyć zrzut sterty, i przefiltruj wyniki, wybierając ustawienie Zduplikowane bitmapy.
Gdy używasz ImageBitmap, przed narysowaniem wywołaj prepareToDraw
Gdy używasz ImageBitmap, aby rozpocząć proces przesyłania tekstury do
procesora graficznego, przed narysowaniem wywołaj ImageBitmap#prepareToDraw(). Pomaga to procesorowi graficznemu przygotować teksturę i poprawić wydajność wyświetlania obrazu na ekranie. Większość bibliotek do wczytywania obrazów wykonuje już tę optymalizację, ale jeśli pracujesz samodzielnie z klasą ImageBitmap, musisz o tym pamiętać.
Zamiast Painter preferuj przekazywanie do elementu kompozycyjnego parametru Int DrawableRes lub adresu URL
Ze względu na złożoność obsługi obrazów (np. napisanie funkcji equals
dla Bitmaps byłoby kosztowne obliczeniowo) interfejs API Painter nie jest
oznaczony jako stabilny za pomocą adnotacji @Stable
. Niestabilne klasy mogą prowadzić do niepotrzebnych ponownych kompozycji, ponieważ kompilator nie może łatwo stwierdzić, czy dane się zmieniły.
Dlatego zalecamy przekazywanie do funkcji kompozycyjnej adresu URL lub identyfikatora obiektu rysowalnego jako parametrów zamiast przekazywania parametru Painter.
// Prefer this:
@Composable
fun MyImage(url: String) {
}
// Over this:
@Composable
fun MyImage(painter: Painter) {
}
Polecane dla Ciebie
- Uwaga: tekst linku jest wyświetlany, gdy język JavaScript jest wyłączony.
- ImageBitmap a ImageVector {:#bitmap-vs-vector}
- Zapisywanie stanu interfejsu w Compose
- Fazy Jetpack Compose