Bitmap allocation, using BitmapFactory.Options.inBitmap throws IllegalArgumentException

sromku picture sromku · Mar 12, 2014 · Viewed 9.2k times · Source

I get the next exception: Problem decoding into existing bitmap, when setting inBitmap to true;

Caused by: java.lang.IllegalArgumentException: Problem decoding into existing bitmap
at android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:460)
...

The interesting thing is that the same code fails in different places when running on:

  • API: 4.4.2, Nexus 4
  • API: 4.3.1, Samsung s3

This is my code which is a copy as it shown in this DevBytes: Bitmap Allocation video.

private BitmapFactory.Options options;
private Bitmap reusedBitmap;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    final ImageView imageView = (ImageView) findViewById(R.id.image_view);

    // set the size to option, the images we will load by using this option
    options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    options.inMutable = true;
    BitmapFactory.decodeResource(getResources(), R.drawable.img1, options);

    // we will create empty bitmap by using the option
    reusedBitmap = Bitmap.createBitmap(options.outWidth, options.outHeight, Bitmap.Config.ARGB_8888);

    // set the option to allocate memory for the bitmap
    options.inJustDecodeBounds = false;
    options.inSampleSize = 1;
    options.inBitmap = reusedBitmap;

    // #1
    reusedBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.img1, options);
    imageView.setImageBitmap(reusedBitmap);

    imageView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

            options.inBitmap = reusedBitmap;
            // #2
            reusedBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.img2, options);
            imageView.setImageBitmap(reusedBitmap);

        }
    });
}

  • Nexus 4, crashes on BitmapFactory.decodeResource() at // #1
  • S3, passes the #1 and display the first image, but crashes later by clicking on image at BitmapFactory.decodeResource() at // #2

Few notes:

  • The images are in the same size. I tried jpg and png. Fails on both.
  • Bitmaps are mutable.
  • I checked by using this canUseForInBitmap method, as described here.

Question:

How to use this inBitmap property properly?

If you met such problem or you see that I made something stupid, please comment/reply. Any help, will be appreciated. If you know about any workaround, it will be great.

- Edit (the question is still open) -

Sorry for not explaining the reason of why I am trying to reuse bitmaps in such way.
The reason for this is GC that locks every time he decides to free memory.
inBitmap feature should help us to reuse bitmap without allocating new memory which will cause GC to clean the already allocated memory.

For example if I use this common approach:

Log.i("my_tag", "image 1");
imageView.setImageResource(R.drawable.img1);
Log.i("my_tag", "image 2");
imageView.setImageResource(R.drawable.img2);
Log.i("my_tag", "image 3");
imageView.setImageResource(R.drawable.img3);

Then this will be GC work:

I/my_tag  ( 5886): image 1
D/dalvikvm( 5886): GC_FOR_ALLOC freed 91K, 2% free 9113K/9240K, paused 15ms, total 15ms
I/dalvikvm-heap( 5886): Grow heap (frag case) to 19.914MB for 11520016-byte allocation
D/dalvikvm( 5886): GC_FOR_ALLOC freed <1K, 1% free 20362K/20492K, paused 13ms, total 13ms
I/my_tag  ( 5886): image 2
D/dalvikvm( 5886): GC_FOR_ALLOC freed 11252K, 2% free 9111K/9236K, paused 15ms, total 15ms
I/dalvikvm-heap( 5886): Grow heap (frag case) to 19.912MB for 11520016-byte allocation
D/dalvikvm( 5886): GC_FOR_ALLOC freed <1K, 1% free 20361K/20488K, paused 35ms, total 35ms
I/my_tag  ( 5886): image 3
D/dalvikvm( 5886): GC_FOR_ALLOC freed 11250K, 2% free 9111K/9236K, paused 15ms, total 15ms
I/dalvikvm-heap( 5886): Grow heap (frag case) to 19.913MB for 11520016-byte allocation
D/dalvikvm( 5886): GC_FOR_ALLOC freed <1K, 1% free 20361K/20488K, paused 32ms, total 32ms

This is more than 100ms of locked main thread!

The same thing will happen if I will decodeResource() without the inBitmap option. So the question is still open, how to use this property ?

Answer

dragi picture dragi · Mar 25, 2014

I tried your code with emulated Nexus 4.
I had default ic_launcher.png file which I copy and pasted it two times in drawable-mdpi (as I usually do). I renamed the two new files to match the names in your code (so that I have less changes to make there).
When I run the application I observed the same as you did.
After few different attempts I decided to copy the the new pngs to other drawable folders - so they were present into:

  • drawable-hdpi
  • drawable-mdpi
  • drawable-xhdpi
  • drawable-xxhdpi

I run the application and it is working!

I am not really sure why it really works, but obviously it has to be something with the correct screen resolution/density.