Question

I've read When should I recycle a bitmap using LRU Cache and several other questions here, and am still struggling with OutOfMemoryExceptions. But I'm getting ahead of myself.

I'm taking over an app that displays a tremendous amount of images. Primarily this is done in an grid view, using a subclassed ArrayAdapter. Images are loaded off the web, using an Asynchronous task, and stored in a cache (which I'll eventually switch to an LRU Cache).

Each picture in the grid view can lead to a detailed view of the image (with more details/UI components), which can lead to another grid view. Eventually there are so many views on the stack that we run out of memory. The cache is being completely flushed of images through the Application.onLowMemory() function, yet despite that, we're running out of memory.

The adapters never check to see if anything is in the cache when recycling views, and I'm sure that could buy me a little bit of breathing room, but it feels like the big gain would be in recycling images in Activities that are 4+ layers back in the stack. The problem is, I'm not sure how to accomplish this. In the onPause routine?

It seems like when the onPause routine is run (switching to the next Activity layer), that the images it was showing will still be in the cache, so they'll not get recycled then. Do I need to pull up the Activity stack and call some custom routine on the older activities at that point to tell them to recycle images?

Additionally, I'm trying to support API levels 9-19. The LRU Cache is provided via the support library for the lower APIs, the full featured one was added in API 12, but apparently if I use the support version, any device running API 12+ won't use the newer version - should I be writing custom code to detect the API version and then use some sort of LRUCache factory to create the version I need? Do I need to write custom code to only do the bitmap recycling on APIs lower than 11?

Was it helpful?

Solution

The solution I eventually went with was this:

I added the support LRU Cache, and then also added Jake Wharton's DiskLRU Cache. Before images were downloaded from the web, first I checked the memory LRUCache, and then the DiskLRUCache. Any image downloaded was stored in both. Next, every Fragment and Activity that owned any images was registered as a listener to the LRU Cache. If the LRU Cache was going to evict an image to make room for another image, it sent a notification to all the listening Fragments and Activities. These listeners then marked their image as 'dirty', meaning they needed to be re-downloaded, and also then called recycle() on the bitmap. This approach seems to work pretty well overall. The app can still get bogged down with garbage collection and eventually after a long time it's still possible to run out of memory on older phones, but it's hard to see where I could improve it any further.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top