22

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;

        }
    } 
Sun
  • 6,768
  • 25
  • 76
  • 131
  • You could simply replace the `Uri` parameter with your filename `String`. That code works with `BitmapFactory.decodeFile` too. – zapl Dec 07 '13 at 13:23
  • @zapl please show me the way – Sun Dec 07 '13 at 13:25
  • santhosh's answer is doing roughly that already. Try it. StackOverflow expects that you have a basic understanding of programming and that you are able to do it yourself. – zapl Dec 07 '13 at 13:28
  • @zapl oh sorry that time i have not seen santosh's answer – Sun Dec 07 '13 at 13:39
  • if you can use the code snippet given in santhosh's answer i believe your problem should have been resolved. Nevertheless here http://developer.android.com/training/displaying-bitmaps/load-bitmap.html is a more detailed version of how you should use those code snippet. – saiful103a Dec 07 '13 at 13:43
  • which solution worked for us solution1 or solution 2 – Shakeeb Ayaz Dec 09 '13 at 04:58

6 Answers6

68

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

Shakeeb Ayaz
  • 6,200
  • 6
  • 45
  • 64
  • 5
    I might be wrong but if bitmap gets recycled right after setImageBitmap shouldn't it throw "Canvas: trying to use a recycled bitmap" error? – saiful103a Dec 07 '13 at 13:58
  • 1
    No but i faced this a lot previously and i am trying to understand how this will help outofmemory issue. As far as i know after setting the bitmap if you do call recycle on bitmap it will not cause any problem as long as system does not invalidate the View. And as you suggested right after setting the bitmap we should call bm.recycle();. Now in that case if user do scroll the list/gridview the system will invalidate everything in the UI and during invalidation the system will not find the pixel data of the imageview. That's where user will get "Canvas: trying to use a recycled bitmap" error? – saiful103a Dec 07 '13 at 14:08
  • @saiful103a have u ever logged getView() to find how getview works or how many time it is called when a listview is called ...One more thing you are not using view holder Design,That can also rise memory issue here is tutorial for view holder https://www.youtube.com/watch?v=OTEiRiMaQ7M .. I am a newbie .U are senior of me If my word are harsh plz pardon me I am ready to correct my self if I am wrong. Watching this video your doubt regarding my ans will be cleared – Shakeeb Ayaz Dec 07 '13 at 14:25
  • @ShakeebAyaz your Solution 2 worked for me, and Shakeeb may i know when i am using device to upload image, it is taking around 1 to 2 mins... how to make it more faster to upload images to server – Sun Dec 09 '13 at 05:01
  • @ShakeebAyaz I ma getting the "Canvas: trying to use a recycled bitmap " error... any idea ? – Thomas Mar 23 '14 at 15:43
  • @ShakeebAyaz Canvas: trying to use a recycled bitmap – Thomas Mar 24 '14 at 08:20
  • @Thomas before using the recycled bitmap again reinitialize the bitmap – Shakeeb Ayaz Mar 24 '14 at 08:50
  • @ShakeebAyaz Even adding this not working, still getting crash. – Narendra Singh Mar 19 '15 at 14:00
  • @ShakeebAyaz I tried the code recommended by Google, in the link above: [Large Bitmaps Efficiently](http://developer.android.com/training/displaying-bitmaps/load-bitmap.html). However sometimes I receive the same error on real devices. I am using an image with 1280x1920, 90 kb... It is too large ?! – fpauer May 13 '15 at 23:10
13

Use this in manifest file in Application tag

android:largeHeap="true"
josliber
  • 43,891
  • 12
  • 98
  • 133
Milan Pansuriya
  • 2,521
  • 1
  • 19
  • 33
7

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);;
}
Community
  • 1
  • 1
Santhosh
  • 1,867
  • 2
  • 16
  • 23
  • i did as you wrote:but getting Multiple markers at this line - reqHeight cannot be resolved to a variable - Syntax error on token "int", delete this token - reqWidth cannot be resolved to a variable - Syntax error on token "strPath", delete this token - String cannot be resolved to a variable - Syntax error on token "int", delete this token at this line: Bitmap bm =decodeSampledBitmapFromResource(String strPath,int reqWidth, int reqHeight); – Sun Dec 07 '13 at 13:34
  • strPath=absolute path of the imagePath in the sdcard try with width and height as 100 x 100 Bitmap bm =decodeSampledBitmapFromResource(strPath,reqWidth,reqHeight) – Santhosh Dec 07 '13 at 13:48
4

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

saiful103a
  • 1,109
  • 7
  • 13
3

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.

Rudra
  • 73
  • 4
  • how would you that in java? – learner Aug 09 '15 at 07:16
  • You don't scale down image in Java, at least I don't know of a way to do it. You can do it in MS Paint or use the Image Compression Feature in MS Photoviewer – Rudra Sep 21 '15 at 03:09
0

Use android:largeHeap="true"in manifest and after creating bitmap bitmap.recycle()

Saurabh Dhage
  • 1,478
  • 5
  • 17
  • 31