View Pager with Universal Image Loader Out of Memory Error
Asked Answered
A

7

11

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;
        }
Altdorfer answered 19/2, 2013 at 13:19 Comment(0)
K
4

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);
Kerley answered 24/2, 2013 at 16:13 Comment(5)
As I mentioned above, I made it work using the implementation mentioned on the github issues link. That has resulted in another bug now, whenever I delete a picture, the exception (Illegal State Exception, ImageView no longer exists, should not use this PhotoViewAttacher anymore) is thrown. Whats weird is that I am returning POSITION_NONE in getItemPosition, not the best of the implementations but good enough for my case, any idea why that is happening here?Altdorfer
for your new exception, see the patch attached: github.com/chrisbanes/PhotoView/pull/34Cabbagehead
Nope, no use, still crashes. Same exception when a page is changed.Altdorfer
Imageloader is still giving me OOM with a ViewPager no matter the configuration. i am loading only jpg <100Ko each store on sd cardGeocentric
Try to disable caching in memory (in DisplayImageOptions.Kerley
E
5

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.

Explain answered 12/3, 2013 at 17:31 Comment(3)
Take into consideration that I'm not using 'ImageLoader.cacheMemory'. If it is a problem.Explain
is not it enough? @Override public void destroyItem(View collection, int position, Object view) { ((ViewPager) collection).removeView((View) view); }Idealize
Should be, but was not enough. Recycling the bitmap solved my crashes although I also believe it is not a very orthodox method.Explain
K
4

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);
Kerley answered 24/2, 2013 at 16:13 Comment(5)
As I mentioned above, I made it work using the implementation mentioned on the github issues link. That has resulted in another bug now, whenever I delete a picture, the exception (Illegal State Exception, ImageView no longer exists, should not use this PhotoViewAttacher anymore) is thrown. Whats weird is that I am returning POSITION_NONE in getItemPosition, not the best of the implementations but good enough for my case, any idea why that is happening here?Altdorfer
for your new exception, see the patch attached: github.com/chrisbanes/PhotoView/pull/34Cabbagehead
Nope, no use, still crashes. Same exception when a page is changed.Altdorfer
Imageloader is still giving me OOM with a ViewPager no matter the configuration. i am loading only jpg <100Ko each store on sd cardGeocentric
Try to disable caching in memory (in DisplayImageOptions.Kerley
E
2

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.

Entoil answered 26/3, 2013 at 8:10 Comment(0)
W
1

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...

Wheeled answered 7/3, 2013 at 13:48 Comment(8)
Not really :/ The problem persists :SAltdorfer
You've already done this step, right? github.com/xeodou/PhotoView/commit/…Wheeled
yeah, but there was no effect of that, let me share the activity code where I am doing all this. And maybe you can tell me what I am doing wrongAltdorfer
Not seeing that you keep instance of photoviews just like i described?Wheeled
any ideas about all this? I am stuck here :/Altdorfer
Didn't use it that library in this way yet, so i'm not sure what is wrong. But i'll try to check your code as soon as i got free time :)Wheeled
oh I just realized you might be working on the wrong problem, I mentioned in one of the comments earlier on another answer that the original problem was FIXED when I used this patch: github.com/chrisbanes/PhotoView/pull/34 but this added a bug to the delete functionality. The problem at hand now is that when an image is deleted from the gallery, it is removed from the SD Card, but the view is not destroyed and stays there, and if I force it to init all views using POSITION_NONE, it gives that error, hope this clears it up if you were still on the out of memory thing.Altdorfer
Now i got it, i was like "there should not be any problem.. hmm.." so your problem is just completely different. Well... I shall no idea then, sorry though.Wheeled
A
0

I used kutothe's implementation from github issues page.

Altdorfer answered 21/2, 2013 at 14:32 Comment(1)
sadly, the link is goneAnnis
K
0

I had this problem when simply setting Uri to ImageView using: iv.setImageURI(Uri.fromFile(imgFile)); I had the same problem with Universal Image Loader, and I even looked for other Image Loaders out there, and found another good one called "Picasso", but it also had the same problem.

So what worked for me is using GestureImageView and setting gesture-image:recycle to true through XML, and load the images with the following code:

            Drawable yourDrawable = null;

            try {
                InputStream inputStream = getActivity().getContentResolver().openInputStream(Uri.fromFile(img));
                yourDrawable = Drawable.createFromStream(inputStream, Uri.fromFile(img).toString() );
                inputStream.close();
            } catch (FileNotFoundException e) {
                yourDrawable = getResources().getDrawable(R.drawable.ic_launcher);
            } catch (IOException e) {
                e.printStackTrace();
            }

            if (yourDrawable != null)
                iv.setImageDrawable(yourDrawable);

the reason it was crashing and giving OOM error is that the bitmaps aren't recycled when the image aren't displayed on the screen anymore, hence a memory leak occurs.

If there is another way to recycle the bitmap in the normal ImageView, that would be a better solution.

Hope I helped.

Kienan answered 10/9, 2013 at 10:29 Comment(0)
Q
-1

I know it's late, but maybe my answer will save someone's time. After hours and hours of trying to solve this issue (with almost every answer found on stack overflow) I finally solved it with Fresco image library. It'a a lib written by Facebook and it's primary goal is to use memory in efficient way. It's really great and my Out Of Memory Error disappeared. I highly recommend using it.

http://frescolib.org/

Quin answered 21/1, 2016 at 18:35 Comment(2)
The answer is not related to the question asked. True, its an alternative library that might be useful to use but doesn't fix the problem mentioned here.Altdorfer
I know, but I wrote this because I had the same exact problem with UIL and View Pager. I spend way too many hours to fix this and the out of memory error still occurred. After I implemented the Fresco lib (took me about 10 minutes) the problem NEVER occurred again. Adding this lib had no negative impact on my project - the worst thing you need to do is to replace ImageView with Fresco's custom view for images, and it's still easy. I replaced UIL with Fresco and I had 0 problems with it. It's easy to use and seems more memory friendly. That's why I recommend it so much, just test it :)Quin

© 2022 - 2024 — McMap. All rights reserved.