Uwaga: istnieje kilka bibliotek, które spełniają wymagania ze sprawdzonymi metodami wczytywania obrazów. Możesz użyć tych bibliotek w swojej aplikacji, aby: najbardziej optymalnie wczytują obrazy. Zalecamy Przesuwanie , która ładuje i wyświetla obrazy tak szybko i płynnie, Inne popularne biblioteki do wczytywania obrazów to Picasso od Square, Coil z Instacart oraz Fryzjer z Facebooka. Te biblioteki upraszczają większość skomplikowanych zadań z mapami bitowymi i innymi typami obrazów na Androidzie.
Obrazy mają różne kształty i rozmiary. W wielu przypadkach są większe niż zwykle interfejsu aplikacji. Na przykład systemowa aplikacja Galeria wyświetla zrobione zdjęcia używając aparatu w urządzeniu z Androidem, który ma zwykle znacznie wyższą rozdzielczość niż ekran. układ pamięci urządzenia.
Biorąc pod uwagę, że masz do czynienia z ograniczoną ilością pamięci, najlepiej przesyłać materiały w niższej rozdzielczości. w pamięci. Wersja w niższej rozdzielczości powinna odpowiadać rozmiarowi komponentu interfejsu, który go wyświetli. Zdjęcie o wyższej rozdzielczości nie przynosi żadnych widocznych korzyści, ale mimo to zużywają cenną pamięć i pochłaniają dodatkowe wymagania związane z wydajnością z powodu
Podczas tej lekcji dowiesz się, jak dekodować duże bitmapy bez konieczności limit pamięci, wczytując w pamięci mniejszą wersję podpróbkowaną.
Odczytywanie wymiarów i typu mapy bitowej
Klasa BitmapFactory
udostępnia kilka metod dekodowania (decodeByteArray()
, decodeFile()
, decodeResource()
itd.) do tworzenia obiektu Bitmap
z różnych źródeł. Wybierz
najbardziej odpowiednią metodę dekodowania na podstawie źródła danych obrazu. Te metody mają na celu
przydzielanie pamięci dla utworzonej mapy bitowej, co może łatwo spowodować OutOfMemory
wyjątek. Każdy typ metody dekodowania ma dodatkowe podpisy, które umożliwiają określenie dekodowania
za pomocą klasy BitmapFactory.Options
. Ustawianie właściwości inJustDecodeBounds
na true
podczas dekodowania
pozwala uniknąć alokacji pamięci, zwracając null
dla obiektu bitmapy, ale ustawiając outWidth
, outHeight
i outMimeType
. Ta metoda pozwala odczytać
wymiarów i typu danych zdjęć przed zbudowaniem (i przydziału pamięci)
bitmapy.
Kotlin
val options = BitmapFactory.Options().apply { inJustDecodeBounds = true } BitmapFactory.decodeResource(resources, R.id.myimage, options) val imageHeight: Int = options.outHeight val imageWidth: Int = options.outWidth val imageType: String = options.outMimeType
Java
BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeResource(getResources(), R.id.myimage, options); int imageHeight = options.outHeight; int imageWidth = options.outWidth; String imageType = options.outMimeType;
Aby uniknąć java.lang.OutOfMemory
wyjątków, sprawdź wymiary mapy bitowej przed
go dekodować, chyba że ufasz źródłu i dostarczysz danych obrazu o przewidywalnych rozmiarach
który wygodnie mieści się w dostępnej pamięci.
Wczytywanie do pamięci wersji skalowanej w dół
Znane są już wymiary obrazu, można więc na ich podstawie zdecydować, czy jego rozmiar wczytywane do pamięci lub powinna zostać wczytana wersja podpróbkowana. Czynniki, które warto wziąć pod uwagę, rozważ:
- Szacowane wykorzystanie pamięci przez wczytanie całego obrazu w pamięci.
- Ilość pamięci, jaką chcesz przeznaczyć na wczytanie tego obrazu na podstawie dowolnej innej pamięci wymagania Twojego zgłoszenia.
- Wymiary docelowego elementu
ImageView
lub komponentu interfejsu, którego dotyczy obraz ma zostać załadowany. - Rozmiar i gęstość ekranu na bieżącym urządzeniu.
Na przykład nie warto ładować obrazu o rozdzielczości 1024 x 768 pikseli do pamięci, jeśli w przyszłości
wyświetlana w miniaturze o wymiarach 128 x 96 pikseli w ImageView
.
Aby nakazać dekoderowi pobieranie podpróbkowanego obrazu przez wczytanie mniejszej wersji obrazu do pamięci, ustaw inSampleSize
na true
w obiekcie BitmapFactory.Options
. Na przykład obraz o rozdzielczości 2048 x 1536, który
jest dekodowane z ustawieniem inSampleSize
o wartości 4, co daje
bitmapa o wymiarach około 512 x 384 piksele. Załadowanie tego pliku do pamięci zajmuje 0,75 MB, a nie 12 MB,
image (przy założeniu, że konfiguracja bitmapy to ARGB_8888
). Oto
metody obliczania wartości rozmiaru próbki, która jest potęgą równa 2, na podstawie szerokości docelowej oraz
wysokość:
Kotlin
fun calculateInSampleSize(options: BitmapFactory.Options, reqWidth: Int, reqHeight: Int): Int { // Raw height and width of image val (height: Int, width: Int) = options.run { outHeight to outWidth } var inSampleSize = 1 if (height > reqHeight || width > reqWidth) { val halfHeight: Int = height / 2 val halfWidth: Int = width / 2 // Calculate the largest inSampleSize value that is a power of 2 and keeps both // height and width larger than the requested height and width. while (halfHeight / inSampleSize >= reqHeight && halfWidth / inSampleSize >= reqWidth) { inSampleSize *= 2 } } return inSampleSize }
Java
public static int calculateInSampleSize( BitmapFactory.Options options, int reqWidth, int reqHeight) { // Raw height and width of image final int height = options.outHeight; final int width = options.outWidth; int inSampleSize = 1; if (height > reqHeight || width > reqWidth) { final int halfHeight = height / 2; final int halfWidth = width / 2; // Calculate the largest inSampleSize value that is a power of 2 and keeps both // height and width larger than the requested height and width. while ((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth) { inSampleSize *= 2; } } return inSampleSize; }
Uwaga: oblicza się potęgę równa 2 wartości, ponieważ dekoder używa
wartość końcową, zaokrąglając w dół do najbliższej potęgi liczby dwóch, zgodnie z dokumentacją funkcji inSampleSize
.
Aby użyć tej metody, najpierw zdekoduj z wartością inJustDecodeBounds
ustawioną na true
, a potem przekaż opcje
przez a następnie ponownie zdekodować z użyciem nowej wartości inSampleSize
i inJustDecodeBounds
ustawionej na false
:
Kotlin
fun decodeSampledBitmapFromResource( res: Resources, resId: Int, reqWidth: Int, reqHeight: Int ): Bitmap { // First decode with inJustDecodeBounds=true to check dimensions return BitmapFactory.Options().run { inJustDecodeBounds = true BitmapFactory.decodeResource(res, resId, this) // Calculate inSampleSize inSampleSize = calculateInSampleSize(this, reqWidth, reqHeight) // Decode bitmap with inSampleSize set inJustDecodeBounds = false BitmapFactory.decodeResource(res, resId, this) } }
Java
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) { // First decode with inJustDecodeBounds=true to check dimensions final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeResource(res, resId, options); // Calculate inSampleSize options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); // Decode bitmap with inSampleSize set options.inJustDecodeBounds = false; return BitmapFactory.decodeResource(res, resId, options); }
Ta metoda ułatwia wczytanie bitmapy o dowolnie dużej wielkości do elementu ImageView
z miniaturą o wymiarach 100 × 100 pikseli. Jak pokazano w tym przykładzie.
kod:
Kotlin
imageView.setImageBitmap( decodeSampledBitmapFromResource(resources, R.id.myimage, 100, 100) )
Java
imageView.setImageBitmap( decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));
W podobny sposób możesz dekodować mapy bitowe z innych źródeł, zastępując
odpowiednią metodę BitmapFactory.decode*
.