Saturday, May 14, 2011

Fixing the "skia decoder->decode returned false" error while downloading images on Android

I had to implement a common requirement in one of my Android project.  I had to show a image that was hosted on the web, in my Android application.  Now that is a very common situation right?  I am sure you must have faced this situation before.

I would have imagined, showing the images from the web would be as simple as setting the correct image source URL to the ImageView.  But as it turns out life is not always that simple. 

So how do we show the images from the web using the ImageView?

  • We have to first download the image using the HttpClient
  • Decode the image data using BitmapFactory and convert it into Bitmap
  • Associate the Decoded Bitmap with the ImageView
Lets look at the code to show the web image in the ImageView

The above code works and works well, it does show the image hosted on the web in the ImageView.  However, sometimes, I get an error in the log saying

Now, this is something unexpected. Whenever I get this error the image download stops and image is not shown in the ImageView.
The Cause:

Googled a little and as usual, I was not the only one to face this issue.  There are lots of threads online, that mention this particular issue (here and here), "decoder returned false". 

It seems that when skip method of the InputStream class does not skip the given number of bytes then, the BitmapFactory fails to decode the InputStream.  Usually, the issue occurs on a slow internet connection.  However, I cant confirm that, I have a 2Mbps dedicated internet connection, even on this connection issue is reproduicable! 

The Fix:

There are two ways of fixing this issue.

Method 1 - Method that involves writing some custom code

This method makes sure that, the skip method of InputStream actually skip's the mentioned number of bytes.

To do this, we will need to wrap the InputStream into a custom class, override the skip method and ensure that we skip the given number of bytes no matter what.  This can be achieved by subclassing the FilterInputStream class and overriding the skip method.  Lets look at how the new implementation of the skip method.

As seen in the above code, the skip method simply makes sure that we skip the give number of bytes.  The class FlushedInputStream now needs to be used while we decode the image. The updated code with the FilteredInputStream looks like

Method 2 - Method that involves using the BufferedInputStream

This method is very simple and straight forward we simply need to wrap the imageContentInputStream with the BufferedInputStream. This also seems to fix the problem. The updated code looks like

Yep, these two methods fix the "decode returned false" issue.
Have some Fun!