2

I'm trying to setImageBitmap but I keep getting the following OutOfMemoryError even after I have implemented the guidelines here https://developer.android.com/topic/performance/graphics/load-bitmap.html:

java.lang.OutOfMemoryError: Failed to allocate a 11345668 byte allocation with 1206384 free bytes and 1178KB until OOM
        at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
        at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
        at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:620)
        at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:455)
        at android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:478)
        at com.example.myapp.ImageOptimized.decodeSampledBitmapFromResource(ImagenOptimizada.java:50)
        at com.example.myapp.Game3Players.onAnimationEnd(Game3Players.java:511)
        at android.view.animation.Animation$3.run(Animation.java:381)
        at android.os.Handler.handleCallback(Handler.java:751)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:154)
        at android.app.ActivityThread.main(ActivityThread.java:6119)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)

This is the part of the code where I use the method. I randomly choose one card to show one image, and the rest will show another:

ImageView[] cardsArray = new ImageView[3];
            cardsArray[0]=cardOne;
            cardsArray[1]=cardTwo;
            cardsArray[2]=cardThree;

            final int index = new Random().nextInt(cardsArray.length);                                
            cardsArray[index].setImageBitmap(ImageOptimized.decodeSampledBitmapFromResource(getResources(), R.drawable.skull, 250, 250));     

            for (int i=0; i<cardsArray.length; i++){                                                  

                if (cardsArray[index]!=cardsArray[i]){
                    cardsArray[i].setImageBitmap(ImageOptimized.decodeSampledBitmapFromResource(getResources(), R.drawable.safe, 250, 250));
                }

            }

I first tried this because, since I'm replacing an image for another, I want to use the same width and height:

cardsArray[index].setImageBitmap(ImageOptimized.decodeSampledBitmapFromResource(getResources(), R.drawable.skull, cardsArray[index].getWidth(), cardsArray[index].getHeight()));

But this was giving me an error right away. That's why I decided to use a fixed size, 250, but it keeps throwing me the error. What's funny is that sometimes the code runs without a problem, but then when the operation is repeated - maybe the third, fourth, sometimes fifth time - it crashes. Am I possibly doing something wrong which leads to a memory leak maybe?

Just in case you also wanna take a look to the class where I follow the guidelines:

public class ImageOptimized {


    public static int calculateInSampleSize(
            BitmapFactory.Options options, int reqWidth, int reqHeight) {
        // Raw height and width of image
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;

        if (height > reqHeight || width > reqWidth) {

            final int halfHeight = height / 2;
            final int halfWidth = width / 2;

            // Calculate the largest inSampleSize value that is a power of 2 and keeps both
            // height and width larger than the requested height and width.
            while ((halfHeight / inSampleSize) >= reqHeight
                    && (halfWidth / inSampleSize) >= reqWidth) {
                inSampleSize *= 2;
            }
        }

        return inSampleSize;
    }


    public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
                                                         int reqWidth, int reqHeight) {

        // First decode with inJustDecodeBounds=true to check dimensions
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeResource(res, resId, options);

        // Calculate inSampleSize
        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

        // Decode bitmap with inSampleSize set
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeResource(res, resId, options);
    }

}
2
  • Where do you have the image? I mean in which folder? Commented Mar 29, 2019 at 16:22
  • drawable folder @Skizo-ozᴉʞS Commented Mar 29, 2019 at 16:22

2 Answers 2

1

You can use loading and caching image libraries for better performance such as Glide or Picasso.

Usage of Glide, for example, is pretty simple:

Glide.with(this).load(R.drawable.safe).into(imageView);

You can resize them too:

Glide.with(this).load(R.drawable.safe).apply(new RequestOptions().override(250, 250).into(imageView);

Most of these libraries handle by their own the cleaning of resources they used; which means that they handle memory efficiently.

Also try not to use very large resolution images and use PNG format if you can choose.

Sign up to request clarification or add additional context in comments.

1 Comment

this ended up being a good way to solve the problem. Thank you.
0

I had the same problem days ago, I missed the copy/paste of my drawable and instead of putting it on drawable-hdpi (for instance) I put it on drawable folder, without extension, moving the drawable to a drawable folder with extension worked for me.

Also you can add these lines into your manifest.xml

android:hardwareAccelerated="false"

android:largeHeap="true"

2 Comments

But that means my images will only be visible on devices with that resolution, if someone views the content from a device that is not hdpi then it will crash right?
No it won't, otherwise what you can do is : NativeScript Image Builder to get the images with all of the extensions.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.