Android: Loading images Super-Fast like WhatsApp – Part 1

Zingoo is a new promising app that will rock your weekends, outings and any happening that you want to easily enjoy watching its moments over & over again (we are now doing the Android version, then the iOS one). Because we want Zingoo to be born strong, it has to deliver the best possible [UX] to all awesome-moments lovers around the world, which means we have to do our best in loading the images.

Because we (at Begether) do listen to our users, we heard a lot of comments on how WhatsApp is loading images super-fast, so we dug deeper to know what we can do about it, & here is what we find,

What does WhatsApp do?
WhatsApp is doing the following (numbers are approximate):

  • Photos sizes range around 100KB, which loads the images pretty fast on most common mobile-network speeds. (part 2 explains how to achieve this)
  • Photos are cached, so no need to load them every time you open the app (almost no need to mention this 🙂 ).
  • They first show a very small thumbnail (about 10KB or less) until the real image is loaded, & this is the real pro-tip for their better UX.

The last tip has a different variance by calculating the image dimensions & the approximate color of the image that will be shown & applying it to its placeholder, like the coming 3 minutes in this video:

but still, the thumbnail is away more cooler, right? 😉

How is it done?
To achieve the caching there are some good Android libraries out there that are doing a good job, but one of them is doing a way better than the others, which is Picasso. Both caching on disk & on memory are built under the hood, with a very developer-friendly API, I just love what Jake Wharton & his mates did for all of us, thanks guys.
Using Picasso is pretty easy, just like this example one-liner:

Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);

you just need first to add Picasso to your gradle files with the urlConnection library (according to this issue), like this:

compile 'com.squareup.picasso:picasso:2.4.0'
compile 'com.squareup.okhttp:okhttp-urlconnection:2.0.0'

After solving the caching issue, we need to apply the thumbnail great tip, we need to use Picasso 2 times, one for loading the thumbnail and the other for loading the real image like the comment I made on this issue. Also to avoid the thumbnail’s pixlation effect (due to its small size), it would be better to make a blurring effect on it,
WhatsApp's Thumbnail Loading Effect

and here is how it is done:

Transformation blurTransformation = new Transformation() {
    @Override
    public Bitmap transform(Bitmap source) {
        Bitmap blurred = Blur.fastblur(LiveImageView.this.context, source, 10);
        source.recycle();
        return blurred;
    }

    @Override
    public String key() {
        return "blur()";
    }
};

Picasso.with(context)
    .load(thumbUrl) // thumbnail url goes here
    .placeholder(R.drawable.placeholder)
    .resize(imageViewWidth, imageViewHeight)
    .transform(blurTransformation)
    .into(imageView, new Callback() {
        @Override
        public void onSuccess() {
            Picasso.with(context)
                    .load(url) // image url goes here
                    .resize(imageViewWidth, imageViewHeight)
                    .placeholder(imageView.getDrawable())
                    .into(imageView);
        }

        @Override
        public void onError() {
        }
    });

We used the Callback() functionality to start loading the full image after the thumbnail is completely loaded, with using the blurred thumbnail’s drawable as the new placeholder for the real image, & this is how the magic is being done right here :).
Also the blurring made here is Blur.fastblur(), thanks to Michael Evans & his EtsyBlurExample example, you can find this class here.

The only remaining part is how to compress the large images (which could be 2 to 4 MB) to be only about 100 KB, which is discussed in Part 2.