Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

View Pager with Universal Image Loader Out of Memory Error

I am not really sure if a ViewPager with Universal Image Loader can/should be used as an alternate for a gallery like interface since I have run into an Out of Memory error while loading images from SD Card and viewing them in full screen mode. No matter what the number, it works all fine with a GridView but while viewing the images in the View Pager, each bitmap keeps eating up a lot of memory and after 10 or so images, it gives the out of memory error.

I have seen almost all the questions that have been posted here related to the Out of Memory Error while working with the Universal Image Loader and in each one of them, there has been a configurations error as the cause.

I dont know if I am using the wrong configurations or what but I have wasted a lot of time on it and am kind of stuck, any help/advice would be appreciated.

The configurations for the ImageLoader:

ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getApplicationContext())
            .memoryCache(new WeakMemoryCache())
            .denyCacheImageMultipleSizesInMemory()
            .discCacheFileNameGenerator(new Md5FileNameGenerator())
            .imageDownloader(new ExtendedImageDownloader(getApplicationContext()))
            .tasksProcessingOrder(QueueProcessingType.LIFO)
//          .enableLogging() // Not necessary in common
            .build();

The Display Image Options are:

options = new DisplayImageOptions.Builder()
            .showImageForEmptyUri(R.drawable.image_for_empty_url)
            .resetViewBeforeLoading()
            .imageScaleType(ImageScaleType.IN_SAMPLE_INT)
            .bitmapConfig(Bitmap.Config.RGB_565)
            .displayer(new FadeInBitmapDisplayer(300))
            .build();

I am using the example project that was given with the library but those settings wont work either, it just crashes after some time. My guess is that there is a specific callback where I have to recycle bitmaps from the views from that are not visible.

EDIT: I know its a memory leak, the views that are not visible are destroyed when they should be but the memory is not released as it should. Heres the implementation of the destroyItem callback, followed the tips given in different questions but still cant find the memory leak.

@Override
        public void destroyItem(View container, int position, Object object) {
//          ((ViewPager) container).removeView((View) object);
            Log.d("DESTROY", "destroying view at position " + position);
            View view = (View)object;
            ((ViewPager) container).removeView(view);
            view = null;
        }
like image 935
Faraz Hassan Avatar asked Feb 19 '13 13:02

Faraz Hassan


4 Answers

It's probably not the best implementation to solve it, but it worked for me. Removing the ImageViews is not enough, so I decided to recycle bitmaps in 'destroyItem':

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
    View view = (View) object;
    ImageView imageView = (ImageView) view.findViewById(R.id.image);
    if (imageView != null) {
        Bitmap bitmap = ((BitmapDrawable) imageView.getDrawable()).getBitmap();
        bitmap.recycle();
        bitmap = null;
    }
    ((ViewPager) container).removeView(view);
    view = null;
}

This does not clean the last 3 active pages when you leave the activity, although I hope that GC takes care of them.

like image 133
txuslee Avatar answered Nov 15 '22 03:11

txuslee


I also used the same library and had same error. As solution, i created a sparseArray to keep photoView instances. And use it like this:

 private SparseArray<PhotoView> photoViewHolder;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
       ...

       photoViewHolder = new SparseArray<PhotoView>();
       ...
 }

private class GalleryPagerAdapter extends PagerAdapter {

@Override
public View instantiateItem(ViewGroup container, int position) { 

        PhotoView photoView = new PhotoView(container.getContext());

        ImageHolder holder = new ImageHolder();
        holder.position = position;
        holder.loaded = false;

        photoView.setTag(holder);
        photoViewHolder.put(position, photoView);

                    // I used LazyList loading
        loader.DisplayImage(items.get(position), photoView);

        // Now just add PhotoView to ViewPager and return it
        container.addView(photoView, LayoutParams.MATCH_PARENT,
                LayoutParams.MATCH_PARENT);

        return photoView;
    }

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
    container.removeView((View) object);
    photoViewHolder.remove(position);
}

@Override
public boolean isViewFromObject(View view, Object object) {
    return view == object;
}

}

And to handle viewPager's listener:

   pager.setOnPageChangeListener(new OnPageChangeListener() { 

    @Override
    public void onPageScrollStateChanged(int position) { 

    } 

    @Override
    public void onPageScrolled(int position, float arg1, int arg2) { 

    } 

    @Override
    public void onPageSelected(int position) { 
        if(photoViewHolder.get(position) != null) {
            ImageHolder holder = (ImageHolder)photoViewHolder.get(position).getTag();
            // Do something...
        }
    } 
});

Hope this helps...

like image 30
yahya Avatar answered Nov 15 '22 03:11

yahya


Try to apply next suggestions:

  1. Use ImageScaleType.EXACTLY
  2. Enable caching on disc (in display options).
  3. Finally try to use .discCacheExtraOptions(maxImageWidthForDiscCache, maxImageHeightForDiscCache, CompressFormat.PNG, 0);
like image 22
nostra13 Avatar answered Nov 15 '22 05:11

nostra13


Just posting this because this question is coming up on Google when searching for UIL and OOP. I had OOP problems no matter what configuration, what solved all my problems were the two classes RecyclingImageView and RecyclingBitmapDrawable from this sample project.

like image 39
fweigl Avatar answered Nov 15 '22 04:11

fweigl