I am writing an app that displays a panorama picture that eventually has several markers on it to display information about certain points.

As the large image crashed the app (I have also another activity in the app that is displaying a large map), I am now trying to display the panorama as a sequence of pages with ViewPager.

I have managed to display the picture in 6 bits and I thought things were going well, but now the app crashes after a few swipes (about 7 to 8) as the memory runs out.

I am pulling my hair out as to why that is as I thought my items would get destroyed once they are off the screen??
I am an absolute noobs and I'm so sorry if I'm being a time waster. I have spent all day reading and trying out solutions from here and elsewhere and I am none the wiser.

I promise I will be a helpful member from now on (or even more so once I actually know what I'm doing).

EDIT:
- In the first activity, I'm displaying an image that is 552kb.
- The six images that I'm displaying in this activity (PanoramaView) are between 309 and 500kb.
- I have used an allocation tracker in Eclipse and all I could see was the memory filling up but the exact data wasn't clear to me
- the crash happens after displaying 7 or 8 images (basically after swiping back and fourth several times)

In case someone comes across this post, here is what seems to have fixed it:
I have change the code to the code from the answer below and I have also cut up my panorama picture into smaller bits so each image is now below 300kb.

What do u mean large image? Can you post stack trace? Is it crash on first image or you success to display some images and than crash? Can you also post layout "farfarright"
–
MikhailiNov 27 '12 at 15:11

I have added some more details above. Any help is greatly appreciated.
–
silverbarbyNov 27 '12 at 15:31

Thank you very much for your code and the link. I have exchanged my code for yours and the problem still persists. I hadn't realised that I was actually using deprecated stuff. I'll see whether I'll get any further by disabling bits.
–
silverbarbyNov 28 '12 at 18:41

try to open close section in my code "imageview"
–
MikhailiNov 28 '12 at 21:04

Well documented question, and even though you seem to have resolved it, here is a tiny bit of potentially useful information.

From you logcat, I detect that you are developing (or at least testing) on Gingerbread (because Honeycomb onwards does not include the "external" part in the output. This is important only because it highlights what is happening to your bitmaps. In Gingerbread, bitmap data is placed in native memory, outside of the heap. Then, a pointer to that data is placed within the heap, along with some other referential information. Deleting every reference to the bitmap will release the referential information (at some point, when System.gc() runs). However, the bitmap data will never be released, unless your device is hit by an asteroid -- or (less dramatic) you call the recycle() method on that bitmap. That call, it should be noted, really does release the native memory, so you really do need to re-create the bitmap from scratch when it is needed again by the ViewPager (most likely in the instantiateItem. Honeycomb and onward place the bitmap data within the stack, which is slightly less annoying. The data is still released only when you recycle() that bitmap (so you have to dig a bit deeper, using DDMS in order to determine what's going on -- for example, I'm currently fighting this same problem on JB, and in ICS, 4.0.3 behaves differently than 4.0.4, but I digress).

It is probably overkill, but my solution was to implement a class to track my bitmaps, and be certain that I had recycled them -- in your case, this would happen when you destroyItem() in the ViewPager.

The key bit is the dumpBitmaps() call (at least for the problem you describe above). If diligently registers all bitmaps, then the dumpBitmaps() call will expose any which require mopping up. If you don't care about where the leak is, and just want it to go away, then you can just call flush() which will remove all the bitmaps.

You will need to place registerBitmap() wherever you create the bitmap. I have had terrible luck with the inflater doing unpredictable things, so I prefer something like:

I have mentioned a couple times doing things asynchronously, and you mentioned that you are new-ish to Android. For completeness, I should mention that I also dislike using AsyncTask, since it has some pretty heavy limitations on multi-threading, and images tend to require lots of multi-threading. So, instead I use an Executor and do something like this (which, you will note, used the method above to do the actual work):

I am getting java.lang.RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap@2affc178 when returning to a previously viewed image (which is now recycled).
–
YarDec 10 '14 at 15:41

@Yar That's weird. Thing is, after destroyItem has been called, the image views it used to contain are not rendered any more. So you must have some other piece of logic that tries to access that bitmap, besides the pager adapter. We can probably figure something out if you provide more detail (at least line numbers and the relevant code)
–
Ivan BartsovDec 15 '14 at 6:38