2

I am setting help screens images at 4 different places in my app. The activity code is the following-

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.help_list);
        int screenType = getIntent().getIntExtra("screenName", 0);
        ImageView imageView = (ImageView) findViewById(R.id.help_image);

        switch (screenType) {
            case 1:
                imageView.setImageResource(R.drawable.help0);
                break;
            case 2:
                imageView.setImageResource(R.drawable.help1);
                break;
            case 3:
                imageView.setImageResource(R.drawable.help2);
                break;
            case 4:
                imageView.setImageResource(R.drawable.help3);
                break;
        }

        findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();
            }
        });

This code executes successfully on most of the devices, but on some devices (for e.g. Samsung), the app crashes with out of memory exception.

I've tried to recycle the Bitmap-

   BitmapDrawable bitmapDrawable = ((BitmapDrawable) imageView.getDrawable());
    if (bitmapDrawable != null) {
        bitmapDrawable.getBitmap().recycle();
    }

But the above code always gives null in the value of bitmapDrawable. How can I fix this OutOfmemory exception?

P.S. The maximum size of the image drawables is 80kb

Jainendra
  • 24,713
  • 30
  • 122
  • 169
  • Answer from: http://stackoverflow.com/questions/27115944/why-my-application-use-all-memory-and-get-outofmemoryerror-failed-to-allocate/27116001#27116001 Maybe adding this line in Manifest on application tags will help you; android:largeHeap="true" – Cüneyt Oct 22 '15 at 10:50
  • @Cüneyt Do I need to use `android:largeHeap` even for setting image on 80kb size? – Jainendra Oct 22 '15 at 10:52
  • 80 kb is not very big size. Actually I think you don't need android:largeHeap but I want to give a advice only. – Cüneyt Oct 22 '15 at 10:58
  • first `largeHeap` is not a real solution, second, 80KB, no, in memory it takes more, see: Daniel Zolnai's answer – Selvin Oct 22 '15 at 11:22
  • make a folder 'drawable-nodpi' and move these images to this folder. Hope it will help you – userDroid Oct 22 '15 at 11:25

2 Answers2

3

What are the pixel sizes of the images? As the images are stored in the java heap, they are not compressed. That means that each pixel of the bitmap can take up to 32 bits = 4 bytes in the heap. So with an image with the size of 1920 x 1080 (maybe you are also targeting large resolution tablets), that is:

1920 x 1080 x 4 bytes = 8294400 bytes, 8.29 megabytes.

Now that might be OK on a tablet, but on an old phone which might have a heap space of 64 Megabytes, you might easily run into OutOfMemoryExceptions.

So what can you do?

  1. If you are targeting phones only, you can resize the images to smaller sizes maybe? This is mainly based on trial and error, also depends on the usage of the image (blurred background image VS an image of a map with important details).

  2. Use a different bitmap config. The default is RGB_8888, which is 8 bits for each channel (ARGB) = 32 bits. If you don't need the alpha channel (transparency), and the image does not have to be super high quality, you should give RGB_565 a try. It has a very small quality decrease, but it's almost unnoticeable. In return it consumes halve the memory (5 + 6 + 5 = 16 bits per pixel).

  3. The most important fix: You can supply different images for different screen densities. So here's an example. Let's say we want to use the FullHD picture from the calculation. For smaller screens we scale it down, saving on memory. There are tools for scaling images down for the different densities, see this question. Following the density guidelines, you could put the following images with the sizes in the given directories:

    • drawable-xxhdpi: 1920x1080
    • drawable-xhdpi: 1280x720
    • drawable-hdpi: 960x540
    • drawable-mdpi: 640x360

    So while the image would take up 8.29 Mb heap space on a large tablet, it would only take up 921 Kb on an older phone, exactly what we wanted. It does come with the cost of increased APK size though, because now it contains 4 images instead of one.

Community
  • 1
  • 1
Daniel Zolnai
  • 16,487
  • 7
  • 59
  • 71
  • So it is not very likely that it was that image. One thing you should note that it is not necessarily that image which is taking up large memory space. It might be that another image of 30 Mb fitted in the memory, but the app just crashed when trying to add another smaller image, so it will point you to the smaller image, because that's when it crashed. – Daniel Zolnai Oct 22 '15 at 11:35
  • Is there a way I can recycle the old image before setting a new one? – Jainendra Oct 22 '15 at 11:39
  • If you use `setImageResource()`, then it is done automatically in the internals of BitmapDrawable (it makes sure that no pointer is kept on the bitmap, making it available for GC collecting). – Daniel Zolnai Oct 22 '15 at 11:54
  • What you should do is make a memory dump when the app is consuming a lot of memory (there is a chart for that in Android Studio), and take a memory dump. Then analyze it. Here's a really nice article about that: http://www.theshiftingbit.com/Fixing-Memory-Leaks-in-Android-Studio – Daniel Zolnai Oct 22 '15 at 11:57
0

I think your problem described well here

or you can change dimension of your image by photoshop to 50x50 etc.

Community
  • 1
  • 1
sj_8
  • 173
  • 1
  • 16