androidimageviewout-of-memoryviewflipper

java.lang.OutOfMemoryError While Displaying image list in viewFlipper


I'm trying to have live tile images in my application. I tested the functionality on some devices (API>22) and they work. But now i'm testing on API 22 and i'm getting the error in the title. I've searched through the site and I found this to be particularly helpful OutOfMemoryExceptionGridView. But I'm loading my images (straight from the res folder) to an array, then using a viewflipper to make the slideshow

How do I change my block of code (to fix the main OOME) since what I linked above uses bitmaps, and I am directly calling the res id.

This is my code:

@Override
    public View onCreateView(LayoutInflater inflater, final ViewGroup container,
                             Bundle savedInstanceState) {

       int[] images = {R.drawable.img1, R.drawable.img2, R.drawable.img3}; //store images into array
        viewFlipper = view.findViewById(R.id.firstTile); //main tile to have slideshow
         for (int image : images) {
            flipperImages(image); //performs the slideshow per image
        }
}
 public void flipperImages(int image) {
        ImageView imageViewFirstTile = new ImageView(getContext());
        imageViewFirstTile.setBackgroundResource(image);
        viewFlipper.addView(imageViewFirstTile);
        viewFlipper.setFlipInterval(12500);
        viewFlipper.setAutoStart(true);
        viewFlipper.setInAnimation(getContext(), android.R.anim.slide_in_left);
        viewFlipper.setOutAnimation(getContext(), android.R.anim.slide_out_right);
    }

How can I fix the main error with this implementation (calling the res id of the images directly)?


Solution

  • If the images can be scaled down to avoid loading the full sized images, I would consider that as a first step. There is no need to load the full-sized Bitmaps into memory if they window in which they're displayed is a fraction of the size. In your current approach, the images are not subsampled and as a result the entire Bitmap is loaded into memory at it's full size. So you have 3 full sized Bitmaps in memory.

    For subsampling an image, see the following code. (Source: https://developer.android.com/topic/performance/graphics/load-bitmap)

    /* reqWidth and reqHeight would be the dimensions of your ImageView or some other preferred dimensions. For example, if your Bitmap is 500 X 500 and your ViewFlipper/ImageView is only 100 X 100, passing 100 as reqWidth and 100 as reqHeight will subsample the image until it's dimensions are close to the 100 X 100. This will largely shrink the size loaded into memory. */ 
    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);
    }
    
    
    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;
    }