3

I'm loading 100 images from Asset folder to an array object. The pictures are quite small (png ~20k each), and im using this code do to it, and to prevent memory leak & optimized performances:

in a loop:

// create resized bitmap from asset resource
        InputStream istr = assetManager.open(pics[i]);
        Bitmap b = BitmapFactory.decodeStream(istr);
        b = Bitmap.createScaledBitmap(b, 240, 240, true);

where pics[i] is a list of filenames which sits in my Asset folder.

The code works for me, but i still receive from time to time Errors from users (i see it on Developer Console errors):

java.lang.OutOfMemoryError: bitmap size exceeds VM budget
at android.graphics.Bitmap.nativeCreate(Native Method)
at android.graphics.Bitmap.createBitmap(Bitmap.java:468)
at android.graphics.Bitmap.createBitmap(Bitmap.java:435)
at android.graphics.Bitmap.createScaledBitmap(Bitmap.java:340)

Is there anything i can do to improve it? or this is Android's world, we can never deliever a perfect application?

Ofershap
  • 687
  • 2
  • 7
  • 22

3 Answers3

2

Bitmaps aren't compressed so they are stored in width * height * 4 bytes. It means that every image uses about 225 KB of memory. 100 images require about 22 MB of memory. The minimal heap size is 16 MB, but devices usually have 24+ MB heap. And this heap is used not only for data but also for activities, view and so on. That means you can't load 100 bitmaps of this size.

Michael
  • 53,859
  • 22
  • 133
  • 139
2

Of course you can improve something: Don't load too much pictures into the memory at the same time (or reduce their size). Some devices don't have much memory available. Your device may have a higher heap limit than some of your customers phones. Therefore it crashes for them when it works for you (see this video for some heap limits [at 4:44]).

You may get the available heap size via ActivityManager.getMemoryClass().

To improve this, test which pictures you need right now (which are displayed) and are which not. Load only the required ones and recycle the bitmaps you don't need anymore.

Also try using the BitmapFactory.decodeResource() and BitmapFactory.Options.inSampleSize. This allows you to load images at a lower resolution directly without loading them at the full size and then resizing them as you did here.

  • BitmapFactory.decodeResource() is for loading images from Res, no? im loading them from Asset – Ofershap Aug 18 '11 at 17:31
  • Thank you for your comment, i've rewrited the code.. im loading the images only when they are displayed. This memory leak problem in android made me write bad code.. – Ofershap Aug 18 '11 at 17:43
  • Hey, oh yes decodeResource() is for drawable resources. Sorry wasn't fully aware that you are using assets here. But there is also a `decodeStream(InputStream is, Rect outPadding, BitmapFactory.Options opts)` function, not sure if it is useful for you, I never used it myself. –  Aug 18 '11 at 20:21
  • Yes it did, that was my solution! i used hotveryspicy's link suggestion, which suggested using options.inSampleSize and since then there are no memory leak errors.. – Ofershap Aug 19 '11 at 10:13
1

As a rule of thumb you should only ever need to show what the user can actually see. Holding anything else (graphics) in memory is just icing on the cake. This is why devices with higher resolution screens will have larger heap sizes available.

For example, on a 320x480 screen, you would only need as a minimum, 320x480x4=614400 (600kb).

Taking this concept into mind, you need to consider whether you need to hold 100 Bitmaps in memory. Is the user looking at 100 Bitmaps at one time? In that case you can reduce the quality of the images without degrading the user experience (there are only so many pixels on the screen). Is the user scrolling through 100 Bitmaps? Then dump and load images dynamically as appropriate (with a bit of caching for smoothness).

There is always a workaround.

Che Jami
  • 5,151
  • 2
  • 21
  • 18
  • Even when i did load images only when user SEE them, it threw that exception. There is some memory leak in loading images in Android – Ofershap Aug 18 '11 at 17:37
  • Thats why i wrote the code (based on some example i saw somewhere): InputStream istr = assetManager.open(pics[i]); Bitmap b = BitmapFactory.decodeStream(istr); b = Bitmap.createScaledBitmap(b, 240, 240, true); – Ofershap Aug 18 '11 at 17:38