0

I am downloading images from the internet which I am displaying in my app. I am saving those images to file so that I can read them from disk instead of accessing the internet again.

On modern devices I am not getting any issues with this approach, but on an older device (which I am intending to target) I am getting an OutOfMemoryError when loading images from file.

The baffling thing is I do not have any issue if the image is downloaded from the internet, just when the bitmap is read in from file. It's like the image is getting much larger when I save it to file or something, but I don't know why.

This is the error I'm getting:

     Caused by: java.lang.OutOfMemoryError: bitmap size exceeds VM budget(Heap Size=9607KB, Allocated=5143KB, Bitmap Size=24888KB)
        at android.graphics.BitmapFactory.nativeDecodeFile(Native Method)
        at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:355)
        at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:434)
        at scave.reforge.img.DBitmap.readBitmap(DBitmap.java:327)
        at scave.reforge.img.DBitmap.updateBitmap(DBitmap.java:306)

This is my code:

/** Our bitmap object. */
protected Bitmap _bitmap;

public void updateBitmap(Context inContext)
{
    // Reset the bitmap for good measure
    if(_bitmap != null)
    {
        _bitmap.recycle();
        _bitmap = null;
    }

    // Grab the cache file provided it exists
    final File imageFile = new File(getBitmapCacheDir(inContext), getFilename());

    // If we had a cache hit, load the bitmap from the cache
    if(imageFile.exists())
        this.readBitmap(imageFile);
    // If we had a cache miss, download the bitmap from the internet and save it in our cache
    else
        this.downloadBitmap().saveBitmap(inContext);
}

private void readBitmap(File inFilePath)
{
    _bitmap = BitmapFactory.decodeFile(inFilePath.getPath());
}

private void downloadBitmap()
{
    // Our input stream
    InputStream in = null;
    try
    {
        // Open the URL stream
        in = new java.net.URL(_url).openStream();

        // Download the bitmap
        _bitmap = BitmapFactory.decodeStream(in);
    }
    catch(Exception e)
    {
        // Log if there was an error
        Log.e("TAG", "Error downloading image", e);

        _bitmap = null;
    }
    finally
    {
        try
        {
            // Close the input stream if it is open
            if(in != null)
                in.close();
        }
        catch(IOException e)
        {
            // Log if there was an error
            Log.e("TAG", "Error closing stream \"in\"", e);
        }
    }
}

private void saveBitmap(Context inContext)
{
    if(_bitmap == null)
        return;

    // Open the cache directory
    File imageFile = new File(getBitmapCacheDir(inContext), getFilename());

    // Our output stream
    FileOutputStream out = null;
    try
    {
        // Open the output stream
        out = new FileOutputStream(imageFile);

        // Write the bitmap to the cache
        _bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
    }
    catch(Exception e)
    {
        // Log if there was an error
        Log.e("saveBitmap()", "Error while saving bitmap : ", e);
    }
    finally
    {
        try
        {
            // Close the output stream
            if(out != null)
                out.close();
        }
        catch(IOException e)
        {
            // Log if there was an error
            Log.e("saveBitmap()", "Error while closing out : ", e);
        }
    }
}

None of the other questions I've found about this sort of error have been able to explain why the app works if I just download from the internet all the time but not if I read bitmaps from file. Any help is appreciated.

Ingulit
  • 1,141
  • 1
  • 10
  • 20
  • Stab in the dark, but have you checked the PPI on the images? I got seemingly random memory crashes on some images on older devices. After a lot of Googling, I opened the images in a photo image editing tool and saw that I had somehow created them at 300 PPI. I fixed the images to a normal level of 72 and *poof*, errors gone. – Nick Schroeder Jun 13 '15 at 05:20

3 Answers3

1

you have to scale down version of bitmap in android image view . you accessing very large size of image with high resolution image . so you have to scale it down version of bitmap and load it in image view. for more info Google is your friend. and please see the android developer site.

use BitmapFactory.option allows you to read the dimensions and type of the image data prior to construction

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.id.myimage, options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
String imageType = options.outMimeType;
mcd
  • 1,434
  • 15
  • 31
0

If you set an very large image resource for instance as a bitmap file for a ImageView, Android automatically scales it down for you and loads the image.

If you expand the bitmap from the file yourself (from a file say...) , you will face this error. The maximum supported size of Canvas in Android is 2048 X 2048 .

You can use the Picasso library for downloading and displaying images. It will automatically detect the size of the ImageView and load the bitmap accordingly.

in your build file, add

compile 'com.squareup.picasso:picasso:2.5.2'

And in your activity/fragment add

Picasso.with(this).load("Image Url/ Local Uri / File").into(ImageView)

or

Picasso.with(this).load("Image Url/ Local Uri / File").fit().into(ImageView)

You can even use Caching as shown here

Community
  • 1
  • 1
Sanket Berde
  • 6,555
  • 4
  • 35
  • 39
0

Bitmap with large image you have to scale image with BitmapFactory.Options.inSampleSize . The sample size is the number of pixels in either dimension that correspond to a single pixel in the decoded bitmap. When you use inSampleSize = 4 it returns an image that is 1/4 the width/height of the original.You can also see the more detail in android developer site.

 try {
        Bitmap bitmap = null;
        if (bitmap != null) {
            bitmap.recycle();
            bitmap = null;
        }
        bitmap = decodeFileWithSmallSize("sdcard_path");
    } 
 catch (OutOfMemoryError e)
    {
        Log.e("TAG",
                "OutOfMemoryError Exception" + e.getMessage());
    }

    //pass your sdcard path where your image is store 
    private Bitmap decodeFileWithSmallSize(String sdcard_path) {
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inSampleSize = 4;
    Bitmap myBitmap = BitmapFactory.decodeFile(sdcard_path, options);
    return myBitmap;
}