10

i am displaying images in listview and getting out of memory error any one guide me what is the solution to this problem here is my code

LogCat

ERROR/AndroidRuntime(1010): java.lang.OutOfMemoryError: bitmap size exceeds VM budget
ERROR/AndroidRuntime(1010):     at android.graphics.BitmapFactory.nativeDecodeByteArray(Native Method)
ERROR/AndroidRuntime(1010):     at android.graphics.BitmapFactory.decodeByteArray(BitmapFactory.java:405)
ERROR/AndroidRuntime(1010):     at android.graphics.BitmapFactory.decodeByteArray(BitmapFactory.java:418)
ERROR/AndroidRuntime(1010):     at com.Adapters.AdapterTours.getView(AdapterTours.java:73)
ERROR/AndroidRuntime(1010):     at android.widget.AbsListView.obtainView(AbsListView.java:1409)
ERROR/AndroidRuntime(1010):     at android.widget.ListView.makeAndAddView(ListView.java:1745)
ERROR/AndroidRuntime(1010):     at android.widget.ListView.fillUp(ListView.java:700)
ERROR/AndroidRuntime(1010):     at android.widget.ListView.fillGap(ListView.java:646)
ERROR/AndroidRuntime(1010):     at android.widget.AbsListView.trackMotionScroll(AbsListView.java:3399)
ERROR/AndroidRuntime(1010):     at android.widget.AbsListView.onTouchEvent(AbsListView.java:2233)
ERROR/AndroidRuntime(1010):     at android.widget.ListView.onTouchEvent(ListView.java:3446)
ERROR/AndroidRuntime(1010):     at android.view.View.dispatchTouchEvent(View.java:3885)
ERROR/AndroidRuntime(1010):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:903)
ERROR/AndroidRuntime(1010):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:942)
ERROR/AndroidRuntime(1010):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:942)
ERROR/AndroidRuntime(1010):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:942)
ERROR/AndroidRuntime(1010):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:942)
ERROR/AndroidRuntime(1010):     at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1691)
ERROR/AndroidRuntime(1010):     at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1125)
ERROR/AndroidRuntime(1010):     at android.app.Activity.dispatchTouchEvent(Activity.java:2096)
ERROR/AndroidRuntime(1010):     at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1675)
ERROR/AndroidRuntime(1010):     at android.view.ViewRoot.deliverPointerEvent(ViewRoot.java:2194)
ERROR/AndroidRuntime(1010):     at android.view.ViewRoot.handleMessage(ViewRoot.java:1878)
ERROR/AndroidRuntime(1010):     at android.os.Handler.dispatchMessage(Handler.java:99)
ERROR/AndroidRuntime(1010):     at android.os.Looper.loop(Looper.java:130)
ERROR/AndroidRuntime(1010):     at android.app.ActivityThread.main(ActivityThread.java:3683)
ERROR/AndroidRuntime(1010):     at java.lang.reflect.Method.invokeNative(Native Method)
ERROR/AndroidRuntime(1010):     at java.lang.reflect.Method.invoke(Method.java:507)
ERROR/AndroidRuntime(1010):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
ERROR/AndroidRuntime(1010):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
ERROR/AndroidRuntime(1010):     at dalvik.system.NativeStart.main(Native Method)

GetView Method

public View getView(final int position, View convertView, ViewGroup parent) {

      ViewHolder holder;

      if (convertView == null) {
        convertView = mInflater.inflate(R.layout.list_tours, null);
        holder = new ViewHolder();
        holder.tourTitle = (TextView) convertView.findViewById(R.id.tourTitle);
        holder.tourIcon = (ImageView) convertView.findViewById(R.id.tourIcon);
        holder.tourDetail = (TextView) convertView.findViewById(R.id.tourDetail);
        convertView.setTag(holder);

      } else {
        holder = (ViewHolder) convertView.getTag();
      }


      DalTours tour = getItem(position);

        String tempTag = String.valueOf(tour.getId());
        holder.tourIcon.setTag(tempTag);

        if(tour.getImageByteArray() != null)
        {
            Bitmap image = BitmapFactory.decodeByteArray(tour.getImageByteArray(), 0, tour.getImageByteArray().length);
            holder.tourIcon.setImageDrawable(getScaledImage(image));
            image = null;

        }else
        {


            holder.tourIcon.setTag(tour);
            Bitmap cachedImage = ImageLoader.loadBitmap(tour,new ImageLoader.ImageCallback() {

                @Override
                public void imageLoaded(Bitmap imageBitmap, DalTours tour) {
                    ImageView image = (ImageView)listview.findViewWithTag(tour);
                     if(image != null)
                      {

                      try
                      {  
                          ByteArrayOutputStream stream = new ByteArrayOutputStream();
                          if(imageBitmap != null)
                          {


                              image.setImageDrawable(getScaledImage(imageBitmap));
                              imageBitmap.compress(CompressFormat.PNG, 0 ,stream);
                              byte[] bitmapdata = stream.toByteArray();
                              tours.get(position).setImageByteArray(bitmapdata);


                         }
                          stream = null;
                      }finally
                      {

                      }
                      }

                }
            });
              holder.tourIcon.setImageDrawable(getScaledImage(cachedImage));

        }

      holder.tourTitle.setText(tours.get(position).getTitle());
      holder.tourDetail.setText(tours.get(position).getDetail());

      return convertView;
    }

image Scale Function

 public Drawable getScaledImage(Bitmap actualBitmap)
    {
        BitmapDrawable bmd= null;
        if(actualBitmap != null)
        {

            int width = actualBitmap.getWidth();
            int height = actualBitmap.getHeight();

            Activity parent = (Activity)context;
            Display display = parent.getWindowManager().getDefaultDisplay(); 
            int Screenwidth = display.getWidth();
            int Screenheight = display.getHeight();


         float newWidth = (Screenwidth*35)/100;

         float temp = newWidth / width;
         float newHeight =  temp * height;



        float scaleWidth = ((float) newWidth) / width;
        float scaleHeight = ((float) newHeight) / height;

        Matrix matrix = new Matrix();

        matrix.postScale(scaleWidth, scaleHeight);
        Bitmap resizedBitmap = Bitmap.createBitmap(actualBitmap, 0, 0, 
                          width, height, matrix, true); 

        bmd = new BitmapDrawable(resizedBitmap);
        }
        return bmd;

    }

Image Loader Class

public  class ImageLoader {
    private static HashMap<String, SoftReference<Bitmap>> imageCache;

    public ImageLoader() {
        //imageCache = new HashMap<String, SoftReference<Bitmap>>();
    }

    public static Bitmap loadBitmap(final DalTours tour, final ImageCallback imageCallback) {
        if(imageCache == null)
            imageCache = new HashMap<String, SoftReference<Bitmap>>();

        if (imageCache.containsKey(tour.getImageurl())) {
            SoftReference<Bitmap> softReference = imageCache.get(tour.getImageurl());
            Bitmap Bitmap = softReference.get();
            if (Bitmap != null) {
                return Bitmap;
            }
        }
        final Handler handler = new Handler() {
            @Override
            public void handleMessage(Message message) {
                imageCallback.imageLoaded((Bitmap) message.obj, tour);
            }
        };
        new Thread() {
            @Override
            public void run() {
                Bitmap Bitmap = loadImageFromUrl(tour.getImageurl());
                imageCache.put(tour.getImageurl(), new SoftReference<Bitmap>(Bitmap));
                Message message = handler.obtainMessage(0, Bitmap);
                handler.sendMessage(message);
            }
        }.start();
        return null;
    }

    public static Bitmap loadImageFromUrl(String url) {

        Bitmap bm;
        try {  

                URL aURL = new URL(url);  
                URLConnection conn = aURL.openConnection(); 

                conn.connect();  
                InputStream is = null;
                try
                {
                 is= conn.getInputStream();  
                }catch(IOException e)
                {
                     return null;
                }

                BufferedInputStream bis = new BufferedInputStream(is);  

                bm = BitmapFactory.decodeStream(bis);  
                bis.close();  
                is.close();  

           } catch (IOException e) {  
            return null;
           }  

           return  bm;


    }

    public interface ImageCallback {
        public void imageLoaded(Bitmap imageBitmap, DalTours tour);
    }
}

any help would be apprecicated

Mr-IDE
  • 7,051
  • 1
  • 53
  • 59
UMAR-MOBITSOLUTIONS
  • 77,236
  • 95
  • 209
  • 278

4 Answers4

25

For Solving java.lang.OutOfMemoryError Exception at android.graphics.BitmapFactory.nativeDecodeByteArray, you should use following Code:

BitmapFactory.Options options=new BitmapFactory.Options();// Create object of bitmapfactory's option method for further option use
options.inPurgeable = true; // inPurgeable is used to free up memory while required
Bitmap songImage1 = BitmapFactory.decodeByteArray(thumbnail,0, thumbnail.length,options);//Decode image, "thumbnail" is the object of image file
Bitmap songImage = Bitmap.createScaledBitmap(songImage1, 50 , 50 , true);// convert decoded bitmap into well scalled Bitmap format.

imageview.SetImageDrawable(songImage);
KeLiuyue
  • 8,149
  • 4
  • 25
  • 42
Jigar
  • 791
  • 11
  • 21
  • 2
    `inPurgeable` is deprecated it seems for newer versions. – David d C e Freitas Nov 02 '14 at 19:56
  • 1
    From https://developer.android.com/reference/android/graphics/BitmapFactory.Options.html : inPurgeable is deprecated.... most apps should avoid using inPurgeable to allow for a fast and fluid UI. To minimize Dalvik heap allocations use the inBitmap flag instead. – user2924714 May 31 '16 at 09:11
6

finally i solve this high resolution image issue which was causing out of memory error using following thread Large Image Manipulation

and here is my code for downloading and scaling image according to your required size.

no more custom scaling function required!!!

public static Bitmap loadImageFromUrl(String url) {

        Bitmap bm;
        try {  

                URL aURL = new URL(url);  
                URLConnection conn = aURL.openConnection(); 

                conn.connect();  
                InputStream is = null;
                try
                {
                 is= conn.getInputStream();  
                }catch(IOException e)
                {
                     return null;
                }

                BufferedInputStream bis = new BufferedInputStream(is);  

                bm = BitmapFactory.decodeStream(bis);

                bis.close();  
                is.close();  

           } catch (IOException e) {  
            return null;
           }  

        return  Bitmap.createScaledBitmap(bm,100,100,true);


    }
Community
  • 1
  • 1
UMAR-MOBITSOLUTIONS
  • 77,236
  • 95
  • 209
  • 278
3

you have to recycle bitmap. The bitmap implementation is native, so the java object is small and a poor candidate for java garbage collection but the memory is still allocated. Taka a look to Bitmap.recycle()

Blackbelt
  • 156,034
  • 29
  • 297
  • 305
  • okey... in order to start.. rule of thumb: Everytime you do not need the bitmap object, call Bitmap.recycle. In your code: in getScaledImage after you create bmd, resizedBitmap and actualBitmap are not longer needed.. so call resizedBitmap.recycle() and actualBitmap.recycle(). Use softreference to get a memory bitmap cache imo is not a good idea (for the native bitmap implementation) – Blackbelt Oct 12 '11 at 09:16
-1

It is definitely a case of having a bitmap for a large image in the memory. If you are repeatedly doing this operation then its good to recycle the bitmap every time. However, just recycling does not guarantee that the memory is freed, its barely marked for garbage collection. So, as an additional step, you should take care of garbage collection too.

Use this code;

Bitmap mybitmap = ....; // you are getting the bitmap here
mybitmap.recycle();
System.gc(); // the above recycling may not be enough always
codeFood
  • 1,241
  • 16
  • 16
  • Calling System.gc() is not a good idea. Read those: http://stackoverflow.com/questions/2414105/why-is-it-bad-practice-to-call-system-gc – Oguz Ozcan May 03 '16 at 13:42