I see a truckload of suggestions for this, but none (that I've found) take all factors into account, the factors being:
- Asynchronous downloading, without duplication (of downloaders and Bitmaps), with canceling downloads/assigning of images that would no longer be needed anyway
- An adapter can have multiple Views for the same ID (calls to getView(0) are very frequent)
- There is no guarantee that a view will not be lost instead of recycled (consider List/GridView resizing or filtering by text)
- A separation of views and data/logic (as much as possible)
- NOT starting a separate Thread for each download (visible slowdown of UI). Use a queue/stack (LinkedBlockingQueue?) and thread pool, or somesuch.... but need to end that if the Activity is destroyed.
- Purging Bitmaps sufficiently distant from the current position in the list/grid, preferably only when memory is needed
- Calling recycle() on every Bitmap that is to be discarded.
- External memory may not be available (at all or all the time), and, if used, should be cleared (of ONLY the images downloaded here) asap. Also consider Activity destruction/recreation by Android.
- Data being changed: entries removed (select in list, button to remove, immediate refresh) and added in a background Thread (list refreshed on demand). Already downloaded Bitmaps should be kept, as long as the entries they're linked to still exist.
- (optional) do not rely on notifyDataSetChanged (which, afaik, refreshes all visible, potentially very complex, list items) for updating a single ImageView
- setTextFilterEnabled(true) (as in ArrayAdapter. Its implementation of Filterable replaces the data array visible to the other Adapter methods, therefore changing indexes of the views, so they cannot be used as IDs to link to the Bitmaps).
- Usable in ExpandableList (affects the order the thumbnails are shown in)
Please forgive me if this had been answered. I've searched for months, and not found a solution.
The requirements seem reasonable to me, but each one adds a dimension of difficulty, especially Bitmap.recycle, which needs to be called during operation and on Activity destruction (note that onDestroy, even onStop might not be called).
This also precludes relying on SoftReferences, which could have taken care of some of the other points.
Yes, it is necessary, or I get OutOfMemoryError even after any number of gc, sleep (20s, even), yield and huge array allocations in a try-catch (to force a controlled low memory situation).
Search for "OutOfMemoryError: bitmap size exceeds VM budget" or "android bitmap recycle".
Yes, I am resampling the Bitmaps.
AsyncTask
class - which taps the internal thread pool that's already available, posting images back as progress updates & doesn't exit until requested by the Activity. Works nicely for 2+. FYI. – Axis