Optymalizacja obrazów bitmapowych

Jeśli nie będziesz ostrożny, 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, zmianie rozmiaru grafiki w razie potrzeby i ponownemu wykorzystywaniu obiektów graficznych.

Zmiana rozmiaru obrazów w razie potrzeby

Upewnij się, że używasz obrazu o odpowiednim rozmiarze. Na przykład nigdy nie należy wczytywać dużego obrazu do małej miniatury. Zamiast tego użyj metody takiej jak inSampleSize, aby wczytać obraz po zmianie próbkowania.

Biblioteki do wczytywania obrazów, takie jak Coil i Glide, domyślnie automatycznie zmieniają próbkowanie. Strategie zmniejszania próbkowania możesz skonfigurować za pomocą ImageLoader (w przypadku biblioteki Coil) lub DownsampleStrategy (w przypadku biblioteki Glide).

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 zwiększyć 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 przezroczystą ramką, 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 Composable 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ć tę opcję za pomocą DecodeFormat. W bibliotece Coil możesz użyć właściwości bitmapConfig.

W miarę możliwości używaj wektorów

W przypadku obrazów składających się z kształtów geometrycznych grafika wektorowa jest znacznie mniejsza niż bitmapa i płynnie skaluje się 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ądzanej puli biblioteki, 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 bitmapami zwolnij je, wywołując metodę Bitmap.recycle i natychmiast odrzucając odwołanie Bitmap, zamiast polegać na czyszczeniu pamięci.

Inne wskazówki i triki

W tej sekcji znajdziesz kilka innych sposobów na zwiększenie wydajności aplikacji podczas obsługi grafiki.

Nie pakuj dużych obrazów w pliku AAB/APK

Jedną z głównych przyczyn dużego rozmiaru pobierania aplikacji jest grafika spakowana w pliku AAB lub APK. Użyj narzędzia do analizy APK, aby sprawdzić , czy nie pakujesz 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 analizatora zrzutu sterty, aby utworzyć zrzut sterty, i przefiltruj wyniki, wybierając ustawienie Duplikaty bitmap.

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 zwiększyć 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 przekazuj do elementu Composable jako parametry Int DrawableRes lub adres 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 jako parametrów adresu URL lub identyfikatora obiektu rysowalnego zamiast Painter.

// Prefer this:
@Composable
fun MyImage(url: String) {

}
// Over this:
@Composable
fun MyImage(painter: Painter) {

}