Byłbym bardzo wdzięczny, gdyby ktoś mógł potwierdzić, że rozwiązałem poniższy problem poprawnie lub czy istnieje alternatywne rozwiązanie?Android Bitmapa ładuje się błąd pamięci Galaxy S3 WXGA
Mam aplikację, która ładuje duży obraz (na przykład 800 * 1720 pikseli) do pamięci i wyświetla go w przewijanym widoku. Obraz jest planem piętra dla muzeum i chciałem stworzyć prostą mapę, taką jak przewijanie i powiększanie. Obraz ładował się dobrze na starszych urządzeniach, ale spowodował błąd braku pamięci na Samsung Galaxy S3.
Patrząc na komunikaty LogCat okazało się, że przy tworzeniu mapy bitowej zostało przydzielone 22 MB dla mapy bitowej zamiast 800 * 1720 * 4 = 5,5 MB. Zasadniczo przydzielono 4x tyle pamięci, ile wymagały inne urządzenia, i popychając wykorzystanie pamięci przez wielkość sterty 50 MB.
Zalecanym rozwiązaniem tego problemu jest użycie opcji BitmapFactory.Options.inSampleSize
w celu zmniejszenia rozdzielczości załadowanego obrazu i uzyskania mniejszej ilości pamięci. Zmniejsza to jednak jakość obrazu, a ja naprawdę chcę wyświetlać go w pełnym rozmiarze w oryginalnej jakości, co działa dobrze na starszych urządzeniach.
Po wielu drapaniach głowy doszedłem do wniosku, że problem polegał na tym, że gęstość pikseli na ekranach WXGA S3 wynosi 2,0, a zatem dla każdego piksela na obrazie bitmapa faktycznie przydzieliła 4 piksele. Przy odrobinie prób i błędów odkryłem mogłem temu zapobiec poprzez ustawienie options.inScaled = false;
http://developer.android.com/reference/android/graphics/BitmapFactory.Options.html#inScaled
Po drodze, ja też sobie sprawę, że mogę obciąć zużycie pamięci w połowie do 2.7MB stosując mniejszą wierność głębia kolorów 2 pikseli zamiast 4 pikseli poprzez ustawienie options.inPreferredConfig = Bitmap.Config.RGB_565;
. Dla moich podłóg nie wpłynęło to na jakość obrazu widzialnego.
Ostateczna Kod było tak:
String uri = "drawable/floorplan";
int imageResource = getResources().getIdentifier(uri, null, getPackageName());
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.RGB_565;
options.inScaled = false;
Bitmap bm = BitmapFactory.decodeResource(getResources(), imageResource, options);
IVfloorplan.setImageBitmap(bm);
Podczas wyświetlania tej bitmapy trzeba go skalować z powrotem do góry. Wypracować skalowanie można uzyskać gęstość pikseli z:
float density = getResources().getDisplayMetrics().density;
I zmniejszone zużycie pamięci dla bitmapy od 22MB do 2.7MB, które w stercie 50MB jest znacząca.
Dobra analiza i dziękuję za rozwiązanie. – Simon
Myślę, że może być dobrze, aby dostarczyć link do dokumentacji, który opisuje częściowo to samo w przypadku inSampleSize: http://developer.android.com/training/displaying-bitmaps/load-bitmap.html. I http://www.curious-creature.org/2010/12/08/bitmap-quality-banding-and-dithering/ o graniu w formatach bitmapowych i ich rekwizytach/wadach. – sandrstar
niesamowite. Myślę, że pomoże to nawet w przypadku innych urządzeń o mniejszych rozmiarach sterty. Ale zamiast dodawać odpowiedzi w odpowiedzi na pytanie, należy dodać odpowiedź, ponieważ narusza ona reguły SO i uniemożliwia usunięcie tego pytania. –