android – How to handle OutOfMemoryError-ThrowExceptions

Exception or error:

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?

How to solve:

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.

###

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.

###

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;
}

###

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

###

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

###

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">

Leave a Reply

Your email address will not be published. Required fields are marked *