8

So, I've been looking at the ImageView source for a while, but I haven't figured out a hook to do this yet.

The problem: having, let's say, 30 400x800 images inside a ScrollView (the number of images is variable). Since they fit exactly in the screen they will take 1.3 MB of RAM each.

What I want: to be able to load/unload bitmaps for the ImageViews that are currently visible inside a ScrollView. If the user scrolls and the bitmap is no longer visible (within a distance threshold) the bitmap should be recycled so that the memory can be used by other bitmaps in the same ScrollView. I'm doing downsampling and all that, so no worries there. Bonus points if you do this by only extending ImageView (I would like to not mess with the ScrollView if possible).

Summary: I can make the images load only after the ImageView becomes visible (using a clever trick), but I don't know when to unload them.

Notes: I can't do this with a ListView due to other usability reasons.

dmon
  • 30,048
  • 8
  • 87
  • 96

3 Answers3

5

Call this method when you want to recycle your bitmaps.

public static void recycleImagesFromView(View view) {
            if(view instanceof ImageView)
            {
                Drawable drawable = ((ImageView)view).getDrawable();
                if(drawable instanceof BitmapDrawable)
                {
                    BitmapDrawable bitmapDrawable = (BitmapDrawable)drawable;
                    bitmapDrawable.getBitmap().recycle();
                }
            }

            if (view instanceof ViewGroup) {
                for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
                    recycleImagesFromView(((ViewGroup) view).getChildAt(i));
                }
            }
        }
Pawan Maheshwari
  • 15,088
  • 1
  • 48
  • 50
  • Thanks for a general answer. But Are you sure this is efficient and not causing a considerable delay? – Hamzeh Soboh Aug 27 '14 at 07:11
  • I added a missing null check because getBitmap() may return null; see BitmapDrawable.java: "Returns the bitmap used by this drawable to render. May be null." – Oliver Hausler Apr 11 '15 at 14:25
1

Have a look at the android documentation about "How to draw bitmaps" Also the code example called bitmap fun.

If you use a ListView or a GridView the ImageView objects are getting recycled and the actual bitmap gets released to be cleaned up by the GC.

You also want to resize the original images to the screen size and cache them on disk and/or RAM. This will safe you a lot of space and the actual size should get down to a couple of hundert KB. You can also try to display the images in half the resolution of your display. The result should still be good while using much less RAM.

philipp
  • 4,133
  • 1
  • 36
  • 35
  • Yeah for ListView it would be the "default" behavior. This was specifically for a ScrollView, I figured it out in the end, but it wasn't pretty. – dmon Oct 23 '12 at 22:14
  • @dmon Can you share any part of your solution? And are you 100% sure that ListView automatically disposes Views as they go out of focus? Does this works for all Android versions or is it something that's 2.2+? – nikib3ro Apr 02 '13 at 20:45
  • the lowest API version I coded against is level 7. I can look to post more info here. Bit bussy right now. But maybe end of the week – philipp Apr 11 '13 at 22:48
0

What you really want is to use an ArrayAdapter for this. If, like your notes suggest, that is not possible (although i don't see why) take a look at the source for array adapter and rewrite one to your own needs.

Paul Nikonowicz
  • 3,883
  • 21
  • 39
  • I already use an array adapter to generate the components that include these ImageViews. The ArrayAdapter by itself does nothing clever. – dmon Dec 02 '11 at 14:54
  • The array adapter releases it's references from all views when the views move out of view (more or less). This will force your images to recycle automatically. You don't need explicitly call recycle on images. However, you need to be sure that there are no strong references to the Bitmaps so that they can be released. – Paul Nikonowicz Dec 02 '11 at 16:28
  • What i've been doing, is just storing the images on the file system, and on getView, bind the bitmap to the view from the filesystem. – Paul Nikonowicz Dec 02 '11 at 16:31
  • Again, this is not the Adapter's doing but whatever is holding the Adapter, in this case probably a ListView. The adapter itself does nothing other than return a new view or reuse the recycled if that is provided. – dmon Dec 02 '11 at 18:21
  • I see your point. And since you don't want to use a ListView you don't want the adapter either. – Paul Nikonowicz Dec 02 '11 at 18:29
  • Look at the source for ListView to see when getView on the adapter is being called. That should tell you how a focused item is being discovered. – Paul Nikonowicz Dec 02 '11 at 18:30