2012-09-29 14 views
24

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.

+3

Dobra analiza i dziękuję za rozwiązanie. – Simon

+0

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

+0

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. –

Odpowiedz

2

Ekran S3 ma naprawdę wysoką rozdzielczość, więc jest całkiem zrozumiały. Ponadto, jeśli obraz znajduje się w folderze do rysowania, może zostać automatycznie przeskalowany do góry. Mogą być sposoby, żeby to wyłączyć. Nawet jeśli rozmiar obrazu nie ma szansy, system operacyjny musi przydzielić bufor, aby pomieścić obraz, a także jeden umożliwiający wyświetlenie go na ekranie.

Alternatywą jest używanie kafelków, które są używane w grach takich jak gry SNES. W ten sposób radzili sobie z dużą ilością grafiki bez wyczerpania pamięci RAM. Dowody pokazują, że w ten sposób Mapy Google mają mapę planety Ziemia. Zasadniczo rozdrabniasz duży obraz na płytki i pokazujesz kafelki na ekranie podczas przesuwania do nich (oczywiście, może 1 dodatkowa płytka z każdej strony).

Mimo że jest to post-Honeycomb, w którym Google umieścił kod, aby lepiej zarządzać przydziałami bitmapowymi, należy zachować ostrożność przy przydzielaniu bitmapy. To bardziej przypomina program w języku C niż program w języku Java i dobrze jest nim zarządzać. Bardzo łatwo jest zabraknąć miejsca na sterty podczas korzystania z obiektów bitmapowych w Androidzie

Powiązane problemy