So I wrote a custom view which displays a list of bitmaps. The way this works is to draw a grid of images by loading them from disk, then drawing those images using Canvas.drawBitmap(Bitmap, Rect, Rect, Paint).
And during scrolling it was dog slow.
So what I did was to pre-scale the images in a weak hash map:
private WeakHashMap fScaledBitmaps = new WeakHashMap(); private Bitmap getScaledBitmap(String url, int cellWidth, int cellHeight) { /* * Check our cache and return if it's present */ Bitmap bmap = fScaledBitmaps.get(url); if (bmap != null) { if ((bmap.getWidth() == cellWidth) && (bmap.getHeight() == cellHeight)) return bmap; // size different; kill bitmap bmap.recycle(); fScaledBitmaps.remove(url); } bmap = ... get our image from interior cache ... if (bmap == null) { // bitmap not present; return null return null; } else { // Bitmap loaded. Now grab the scaled version Bitmap scale = Bitmap.createScaledBitmap(bmap, cellWidth, cellHeight, true); bmap.recycle(); fScaledBitmaps.put(url, scale); return scale; } }
And this sped up scrolling from sluggish drawing once a second to quick and smooth.
Lesson: drawing a scaled image to a canvas is frighteningly expensive. Like an order of magnitude slower than pre-scaling the bitmap and storing it in a weak reference or weak hash map.
Not a good idea for apps working with lot of bitmaps running on low end devices having low memory
LikeLike
Behind the scenes I’m doing a lot more than what I’ve described here, for the purposes of clarity.
Specifically when I download an image from the remote server, I spool it to a temporary file, and rely on the GC to release the bitmaps from the weak association when memory runs low. In practice this seems to work okay, even on my low end test devices, though you do have to monitor how much temporary file space you’re using and aggressively prune the older files when using beyond a certain threshold.
LikeLike