In this blog post, we demonstrate some simple ways to efficiently display images.
The Straightforward Approach
The simplest way to load an image (e.g. from resource), is to load it in an AsyncTask, and updates the ImageView in onPostExecute():
This works fine until you try to load some large image, when the image refuses to be loaded with this error from logcat:
W/OpenGLRenderer﹕ Bitmap too large to be uploaded into a texture (4000×3726, max=2048×2048)
And of course, it might even throw an OutOfMemory error on low-end devices.
Load a Scaled Image
To solve the problem, we should request the decoder to subsample the original image, as shown below with the updated doInBackground():
This works pretty fine in most cases, until the ImageView is used e.g. inside a ListView, which recycles child views for performance reasons. In this scenario, each time the ImageView is displayed, it will trigger an image load task. However, the sequence when the tasks are finished is undefined. So there is a chance that the image displayed actually comes from the previous item, which for some reason takes longer to load.
To solve this issue, the ImageView should remember the last image it’s supposed to load, so we extends the class and introduces a simple loadImageResource() method as below:
Now everything works fine, except that whenever our ImageView get recycled, it needs to load the image again, so we introduce a simple image cache:
With the above simple ImageCache, one can easily caches images in memory, and improves the performance significantly.