Question

I am working on a code sample where I have to choose an image from gallery the code is working but after selection of image from gallery I get OutOfMemoryError in my OnActivityResult

I am able to get small images but large images are creating problem.

Here is my code:

try{
                    Uri selectedImageUri = data.getData();
                    String[] filePathColumn = {MediaStore.Images.Media.DATA};
                    Cursor cursor = getContentResolver().query(selectedImageUri, filePathColumn, null, null, null);
                    cursor.moveToFirst();
                    int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
                    String filePath = cursor.getString(columnIndex);
                    cursor.close();
                    bitmap = BitmapFactory.decodeFile(filePath);
                    _profileImage.setImageBitmap(bitmap);
                    _profileImage.setScaleType(ScaleType.FIT_XY);
                    Constant._addPhotoBitmap=bitmap;
                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
                    Bitmap resizedbitmap = Bitmap.createScaledBitmap(bitmap, 200, 200, true);
                    resizedbitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
                    byte [] _byteArray = baos.toByteArray();
                    String base64 = Base64.encodeToString(_byteArray,Base64.DEFAULT);
                    Constant._addPhotoBase64 = base64;
                }catch (OutOfMemoryError e) {
                    e.printStackTrace();
                    Constant.showAlertDialog(Constant.errorTitle,
                            "Image size is too large.Please upload small image.",
                            DriverProfileScreen.this, false);
                }   catch (Exception e) {
                    e.printStackTrace();
                }
Was it helpful?

Solution

You are deirectly decoding the file based on its uri path..thats why it is throwing exception..before loading image set some options..this will reduce the memory for the image loading..Use this method for loading image whatever size you want..

/**
 * returns the thumbnail image bitmap from the given url
 * 
 * @param path
 * @param thumbnailSize
 * @return
 */
private Bitmap getThumbnailBitmap(final String path, final int thumbnailSize) {
    Bitmap bitmap;
    BitmapFactory.Options bounds = new BitmapFactory.Options();
    bounds.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(path, bounds);
    if ((bounds.outWidth == -1) || (bounds.outHeight == -1)) {
        bitmap = null;
    }
    int originalSize = (bounds.outHeight > bounds.outWidth) ? bounds.outHeight
            : bounds.outWidth;
    BitmapFactory.Options opts = new BitmapFactory.Options();
    opts.inSampleSize = originalSize / thumbnailSize;
    bitmap = BitmapFactory.decodeFile(path, opts);
    return bitmap;
}

OTHER TIPS

In Android Developer document there is Topic called

Displaying Bitmaps Efficiently

So please go through it.

http://developer.android.com/training/displaying-bitmaps/index.html

Hope this will help you.

Generally android device heap size is only 16MB (varies from device/OS see post Heap Sizes), if you are loading the images and it crosses the size of 16MB , it will throw out of memory exception, instead of using the Bitmap for , loading images from SD card or from resources or even from network try to using getImageUri , loading bitmap require more memory , or you can set bitmap to null if your work done with that bitmap.

So,You need to downscale you image using below code:

public static Bitmap decodeFile(File f,int WIDTH,int HIGHT){
 try {
     //Decode image size
     BitmapFactory.Options o = new BitmapFactory.Options();
     o.inJustDecodeBounds = true;
     BitmapFactory.decodeStream(new FileInputStream(f),null,o);
     //The new size we want to scale to
     final int REQUIRED_WIDTH=WIDTH;
     final int REQUIRED_HIGHT=HIGHT;
     //Find the correct scale value. It should be the power of 2.
     int scale=1;
     while(o.outWidth/scale/2>=REQUIRED_WIDTH && o.outHeight/scale/2>=REQUIRED_HIGHT)
         scale*=2;
     //Decode with inSampleSize
     BitmapFactory.Options o2 = new BitmapFactory.Options();
     o2.inSampleSize=scale;
     return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
 } catch (FileNotFoundException e) {}
 return null;
 }

Scale the bitmap first , then load it. It will solve the problem.

You can use the following method to do that.

private Bitmap getScaledBitmap(Uri uri){
        Bitmap thumb = null ;
        try {
            ContentResolver cr = getContentResolver();
            InputStream in = cr.openInputStream(uri);
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inSampleSize=8;
            thumb = BitmapFactory.decodeStream(in,null,options);
        } catch (FileNotFoundException e) {
            Toast.makeText(PhotoTake.this , "File not found" , Toast.LENGTH_SHORT).show();
        }
        return thumb ; 
    }

Hope it helps.

try this code:

import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import android.app.ActivityManager;
import android.content.ComponentCallbacks;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.support.v4.util.LruCache;
import android.widget.ImageView;

public class UserImageLoaderWithCache implements ComponentCallbacks {
private KCLruCache cache;

public UserImageLoaderWithCache(Context context) {
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
int memoryClass = am.getMemoryClass() * 1024 * 1024;
cache = new KCLruCache(memoryClass);
}

public void display(String url, ImageView imageview, int defaultresource) {
imageview.setImageResource(defaultresource);
Bitmap image = cache.get(url);
if (image != null) {
imageview.setImageBitmap(image);
}
else {
new SetImageTask(imageview).execute(url);
}
}

private class KCLruCache extends LruCache<String, Bitmap> {

public KCLruCache(int maxSize) {
super(maxSize);
}
}

private class SetImageTask extends AsyncTask<String, Void, Integer> {
private ImageView imageview;
private Bitmap bmp;

public SetImageTask(ImageView imageview) {
this.imageview = imageview;
}

@Override
protected Integer doInBackground(String... params) {
String url = params[0];
try {
bmp = getBitmapFromURL(url);
if (bmp != null) {
cache.put(url, bmp);
} else {
return 0;
}
} catch (Exception e) {
e.printStackTrace();
return 0;
} catch (OutOfMemoryError o) {
o.printStackTrace();
return 0;
}
return 1;
}

@Override
protected void onPostExecute(Integer result) {
if (result == 1) {
imageview.setImageBitmap(bmp);
}
super.onPostExecute(result);
}

private Bitmap getBitmapFromURL(String src) {
try {
URL url = new URL(src);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.connect();
InputStream input = connection.getInputStream();
Bitmap myBitmap = BitmapFactory.decodeStream(input);
return myBitmap;
} catch (Exception e) {
e.printStackTrace();
return null;
}catch (OutOfMemoryError o) {
o.printStackTrace();
return null;
}
}
}

public void onLowMemory() {
}

/*public void onTrimMemory(int level) {
if (level >= TRIM_MEMORY_MODERATE) {
cache.evictAll();
}
else if (level >= TRIM_MEMORY_BACKGROUND) {
cache.trimToSize(cache.size() / 2);
}
}*/

public void onConfigurationChanged(Configuration arg0) {
// TODO Auto-generated method stub

}
}

I have used below code and used bitmap to store resized Image in local storage and It worked like charm

final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inSampleSize = 8;

        Bitmap b = BitmapFactory.decodeFile(path, options);

here path is image Uri path in String

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top