android – java.lang.OutOfMemoryError – BitmapFactory.decode(strPath)-ThrowExceptions

Exception or error:

I am getting java.lang.OutOfMemoryError, whenever i am calling UploadActivity.java

Line Number 176 is:

  Bitmap bm = BitmapFactory.decodeFile(strPath);

View my Log:

12-07 17:57:10.585: E/AndroidRuntime(16708): FATAL EXCEPTION: main
12-07 17:57:10.585: E/AndroidRuntime(16708): java.lang.OutOfMemoryError
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:650)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:389)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:449)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at com.example.camera.UploadActivity$ImageAdapter.getView(UploadActivity.java:176)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.widget.AbsListView.obtainView(AbsListView.java:2465)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.widget.ListView.makeAndAddView(ListView.java:1775)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.widget.ListView.fillDown(ListView.java:678)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.widget.ListView.fillFromTop(ListView.java:739)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.widget.ListView.layoutChildren(ListView.java:1628)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.widget.AbsListView.onLayout(AbsListView.java:2300)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.view.View.layout(View.java:14063)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.view.ViewGroup.layout(ViewGroup.java:4607)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.widget.RelativeLayout.onLayout(RelativeLayout.java:948)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.view.View.layout(View.java:14063)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.view.ViewGroup.layout(ViewGroup.java:4607)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.widget.FrameLayout.onLayout(FrameLayout.java:448)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.view.View.layout(View.java:14063)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.view.ViewGroup.layout(ViewGroup.java:4607)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1655)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1513)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.widget.LinearLayout.onLayout(LinearLayout.java:1426)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.view.View.layout(View.java:14063)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.view.ViewGroup.layout(ViewGroup.java:4607)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.widget.FrameLayout.onLayout(FrameLayout.java:448)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.view.View.layout(View.java:14063)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.view.ViewGroup.layout(ViewGroup.java:4607)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:1996)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1817)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1114)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:4520)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.view.Choreographer$CallbackRecord.run(Choreographer.java:725)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.view.Choreographer.doCallbacks(Choreographer.java:555)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.view.Choreographer.doFrame(Choreographer.java:525)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:711)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.os.Handler.handleCallback(Handler.java:615)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.os.Handler.dispatchMessage(Handler.java:92)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.os.Looper.loop(Looper.java:137)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.app.ActivityThread.main(ActivityThread.java:4921)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at java.lang.reflect.Method.invokeNative(Native Method)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at java.lang.reflect.Method.invoke(Method.java:511)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1036)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:803)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at dalvik.system.NativeStart.main(Native Method)

UploadActivity.java:-

public class ImageAdapter extends BaseAdapter
        {
        private Context context;

        public ImageAdapter(Context c)
        {
        // TODO Auto-generated method stub
        context = c;
        }

        public int getCount() {
        // TODO Auto-generated method stub
        return ImageList.size();
        }

        public Object getItem(int position) {
        // TODO Auto-generated method stub
        return position;
        }

        public long getItemId(int position) {
        // TODO Auto-generated method stub
        return position;
        }

        public View getView(final int position, View convertView, ViewGroup parent) {
        // TODO Auto-generated method stub

        LayoutInflater inflater = (LayoutInflater) context
        .getSystemService(Context.LAYOUT_INFLATER_SERVICE);      

        if (convertView == null) {
        convertView = inflater.inflate(R.layout.list_upload, null);
        }


        // ColImgName
        TextView txtName = (TextView) convertView.findViewById(R.id.ColImgName);
        strPath = ImageList.get(position).toString();

        // Get File Name
        fileName = strPath.substring( strPath.lastIndexOf('/')+1, strPath.length() );
        File file = new File(strPath);
        @SuppressWarnings("unused")
        long length = file.length();
        txtName.setText(fileName);

        // Image Resource
        ImageView imageView = (ImageView) convertView.findViewById(R.id.ColImgPath);
        Bitmap bm = BitmapFactory.decodeFile(strPath);
        imageView.setImageBitmap(bm);


        // ColStatus
        final ImageView txtStatus = (ImageView) convertView.findViewById(R.id.ColStatus);
        txtStatus.setImageResource(R.drawable.bullet_button);

        // progressBar
        final ProgressBar progress = (ProgressBar) convertView.findViewById(R.id.progressBar);
        progress.setVisibility(View.GONE);

        //btnUpload
        final ImageButton btnUpload = (ImageButton) convertView.findViewById(R.id.btnUpload);
        btnUpload.setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {
        // Upload
        btnUpload.setEnabled(false);

        startUpload(position);
        }
        });

        return convertView;

        }
    } 
How to solve:

You need to recycle Bitmap object .

    Bitmap bm = BitmapFactory.decodeFile(strPath);
    imageView.setImageBitmap(bm);

After above lines of code in your get view just add the code written below
///now recycle your bitmap this will free up your memory on every iteration

    if(bm!=null)
   {
     bm.recycle();
     bm=null;
    }

After this also if you are getting same error the

Replace below code

    Bitmap bm = BitmapFactory.decodeFile(strPath);
    imageView.setImageBitmap(bm);

with

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

Bitmap bm = BitmapFactory.decodeFile(strPath,options);
imageView.setImageBitmap(bm);

Use inSampleSize to load scales bitmaps to memory. Using powers of 2 for inSampleSize values is faster and more efficient for the decoder. However, if you plan to cache the resized versions in memory or on disk, it’s usually still worth decoding to the most appropriate image dimensions to save space.

For more see Loading Large Bitmaps Efficiently

###

Use this in manifest file in Application tag

android:largeHeap="true"

###

before calling Bitmap bm=BitmapFactory.decodeFile(strPath);

call this.. Bitmap bm =decodeSampledBitmapFromResource(strPath,reqWidth,reqHeight);

if you get again java.lang.OutOfMemoryError then let me know

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

public static Bitmap decodeSampledBitmapFromResource(String strPath,int reqWidth, int reqHeight) {

        // First decode with inJustDecodeBounds=true to check dimensions
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(strPath, options);
        // Calculate inSampleSize
        options.inSampleSize = calculateInSampleSize(options,reqWidth,
                reqHeight);
        // Decode bitmap with inSampleSize set
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeFile(strPath, options);;
}

###

It’s an optimisation problem for your application. You are getting OutOfMemoryError because when you are doing BitmapFactory.decodeFile(strPath) android is trying to allocate memory for that bitmap. In your case system can’t find enough free space to allocate and that’s why you are getting this error.

Now as i can see from your code you are trying to show list of images using ImageAdapter. In that case your imageview must have smaller width and height than actual image.

To give you a more generalised idea here’s what is happening:

  • ImageView width * height = 100dp * 100dp
  • Image width * height = 800px * 800px.

In this scenario though our imageview width-height is 100 * 100 but we are trying to set 800*800 image as it’s background. And this definitely is not an efficient way because the system will allocate memory for 800*800px image whereas 100*100 would do.

That’s why before you do any decoding of bitmap you should sample the bitmap so that only 100*100 worth of memory is allocated.

You will find a more detail version of this explanation here

###

I had the same problem. I incorporated all the above suggestions, but I still had the problem of java.lang.outOfMemoryError. After a lot of tweaking around, what finally worked was scaling down image dimensions (and size).
Originally, I had images of dimensions 800 x 1000 sorts. I rescaled them to about 60 x 80 (because that’s what I needed), and it worked!

So besides following all advice you get on stackoverflow and other sites about this issue, also do a grassroots check of your image sizes and dimensions. Will save you a lot of headache.

Leave a Reply

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