26

In my application I have photos, videos, etc.. In the case of images, I have done scaling, but sometimes I get an OutOfMemoryError. How can I handle the error efficiently?

2

6 Answers 6

33

Check that the image size is smaller than the available memory before attempting to load it. So the most efficient way to handle OutOfMemoryException is to architecture your application in such a way that it never attempts to load lots of data into memory in order to avoid the exception.

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

Comments

9

There is a method in Activity which is called when the device is coming low of memory, but this can only be used to trigger cache files cleaning. This does not mean that your application process is coming out of memory.

You could also add a try catch block to catch Error or OutOfMemoryError, but this would be too late.

Handling large numbers of Bitmaps or large Bitmaps is really difficult in android applications. You'll find some tips on this subject in this article from Romain Guy.

You can also take care of loading bitmaps directly to the resolution you need by specifying a sample size in the BitmapFactory.options you provide to BitmapFactory.decode*() methods.

1 Comment

Notice that onLowMemory is called just when another application needs more memory. Not when your application is out of memory. So onLowMemory will not be invoked when OutOfMemoryError is thrown.
4

When dealing with OutOfMemory errors related to bitmap manipulation, checking the size of the decoded bitmap is the best and as far I know only option. Code follows:

public static BitmapFactory.Options getBitmapOptionsWithoutDecoding(String url){
    BitmapFactory.Options opts = new BitmapFactory.Options();
    opts.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(url, opts);
    return opts;
}

public static int getBitmapSizeWithoutDecoding(String url){
    BitmapFactory.Options opts = getBitmapOptionsWithoutDecoding(url);
    return opts.outHeight*opts.outWidth*32/(1024*1024*8);
}

//ref:http://stackoverflow.com/questions/6073744/android-how-to-check-how-much-memory-is-remaining
public static double availableMemoryMB(){
    double max = Runtime.getRuntime().maxMemory()/1024;
    Debug.MemoryInfo memoryInfo = new Debug.MemoryInfo();
    Debug.getMemoryInfo(memoryInfo);
    return (max - memoryInfo.getTotalPss())/1024;
}

public static final long SAFETY_MEMORY_BUFFER = 10;//MB

public static boolean canBitmapFitInMemory(String path){
    long size = getBitmapSizeWithoutDecoding(path);
    Log.d(TAG, "image MB:"+size);
    return size <= availableMemoryMB() - SAFETY_MEMORY_BUFFER;
}

ref: http://developer.android.com/training/displaying-bitmaps/load-bitmap.html

Comments

2

I have started to try this routine which loads a jpeg into an ImageView and checks for Out of Memory and re-scales until it fits.

 static public boolean tryJpegRead(ImageView imageView, File fn){
 if (!fn.exists()){ 
     Log.d("ANDRO_ASYNC",String.format("missing file %s",fn.getAbsolutePath()));
     return false;
 }
 BitmapFactory.Options o = new BitmapFactory.Options();
    for (int i = 1; i<10; i++){
        o.inSampleSize = i;
        o.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(fn.getAbsolutePath(), o);
        int h = o.outHeight;
        int w = o.outWidth;
        Log.d("ANDRO_ASYNC",String.format("going in h=%d w=%d resample = %d",h,w,o.inSampleSize));
        o.inJustDecodeBounds = false;
        try{
            imageView.setImageBitmap(
                Bitmap.createScaledBitmap(
                        BitmapFactory.decodeFile(fn.getAbsolutePath(), o), 
                        w, 
                        h, 
                        true)); 
            return true; // only happens when there is no error
        }catch(OutOfMemoryError E){
            Log.d("ANDRO_ASYNC",String.format("catch Out Of Memory error"));
    //      E.printStackTrace();
            System.gc();
        }           
    }
    return false;
}

1 Comment

The idea is nice. Does it add any latency ?
2

In case you have big images like backgrounds or similar, a easy way to prevent Out Of Memory , is to move images from drawable-xhdpi to drawable-nodpi , but take care, this will load the bitmap without any modification. The good way should be used BitmapFactory.options to fit your necessity

Comments

2

Use android:allowBackup="true", android:hardwareAccelerated="false" and android:largeHeap="true" for solve this

 <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher"
        android:hardwareAccelerated="false"
        android:largeHeap="true"
        android:theme="@style/AppTheme">

2 Comments

Why android:hardwareAccelerated="false" ?
Also allowBackup isn't relevant out of memory exceptions.

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.