Sunday, July 31, 2016

Image loading with Glide


Image loading seems like an easy task at the first glance but as every task, it has its' own caveats.

First of all, you probably want to do this asynchronously because you don't want to flood your main thread with that kind of tasks.

Then, you want to cache images so you don't load them every time your activity of fragment resumes.

You need to handle error cases when the network is not available or server is sending you garbage or doesn't send anything at all. If you don't do this it will definitely harm the user-experience.

After all, you probably need to do some pre-processing steps before showing the image to the user such as cropping, resizing, reversing etc. Also, it would be convenient to have an easy way to set an image in an ImageView.

You may ask: "Why do you think that you know what I need and want?". The answer is that you're not alone. Android developers already made tons of apps that use pictures from the network.

And what happens when many developers are facing the same problem? Right, they make (most likely an open source) library.

The libraries

There are many libraries that solve the problem and, on the high level, they do it pretty much similar. For example, if you just want to load the image in the image view you will write something like this

String imageUrl 
    = "http://i1.kym-cdn.com/photos/images/facebook/000/002/109/orly_owl.jpg";
LibraryClass.with(context).load(imageUrl)
    .into(imageView);

No matter what concrete library you use (except it's something really exotic).

The most popular ones are Picasso, ImageLoader, Glide, and Fresco (made by Facebook). It's hard to say which one is the best one and developers say that picking one is the matter of taste. But I think that it's worth to mention that Gilde and Fresco support gif loading and Glide is recommended by Google.

Facebook engineers also say that Fresco is more optimized in terms of memory usage but when considering this note that Fresco is not as well tested as Picasso, Glide, and ImageLoader (which is the oldest one).

To show examples I will use Glide because I have been working with it.

Image Loading

First of all, to use Glide you need to add a Gradle dependency.

compile 'com.github.bumptech.glide:glide:3.7.0'

There are several ways you can use an image in your app. You can load it directly in an image view or save its' bitmap to use it anywhere else, for example, in a notification.

Let's consider first use-case. To simply load an image in an image view you must write exactly the code above except you must change LibraryClass to Glide that is it will look like this 

Glide.with(requester).load(imageUrl)
    .into(imageView);

I intentionally changed context to requester to emphasize that it could be not context. with() methods accepts Activity, Context, or Fragment as an argument which in my opinion is very handy.

There are many small features that will make UX of your app much better. For example placeholders, you definitely don't want your user to watch on the empty screen while your images are loading, your app should indicate that it's loading something to show to the user. Placeholders are the great way to do that. It can be a message that says that image is loading, loading animation or simple gray pane that shows that something should be there.

And placeholders are really well implemented in Glide (as well as other libraries) and it's easy to use. That's how it's done.

Glide
    .with(requester)
    .load(imageUrl)
    .placeholder(R.drawable.image_placeholder)
    .into(imageView);

You can show error image (the image that should be shown if something went wrong) using the same way

Glide
    .with(requester)
    .load(imageUrl)
    .error(R.drawable.image_error)
    .into(imageView);

In both of these methods, you can pass a Drawable object as the argument instead of resource id.

The second feature that can enhance UX of your app is animations. When your image appears out of nowhere in a blink of an eye it's kinda little disturbing and doesn't look like things act in the real world, which is a violation of Material Design guidelines.

In Glide as well as many other libraries there is a built-in way to animate the appearance of your images. In Glide you can do this using crossFade() method.

Glide
    .with(requester)
    .load(imageUrl)
    .placeholder(R.drawable.image_placeholder)
    .error(R.drawable.image_error)
    .crossFade()
    .into(imageView);

Also, you can pass an int as an argument to set the duration of the fade animation.

Load as Bitmap

To load image as bitmap you just need to use method asBitmap() set the constraints and use get() like this


Glide
    .with(requester)
    .load(imageUrl)
    .asBitmap()
    .placeholder(R.drawable.image_placeholder)
    .error(R.drawable.image_error)
    .into(width, height)
    .get();

Note that get() should be used only in a background thread which, in my opinion, is fair. If you don't use your image in UI why would you download it in UI thread?

Summary

Image loading includes many steps that cannot be removed from the process and these steps sometimes, not hard but dreary to implement. But the code as everything else ever written is (if properly constructed) reusable and programmers make new libraries every day since the beginning of the programming era.

Libraries as Glide make it possible to load images in just one line of code providing you with the instruments that will make your users' experience better. 

P.S. If you want to dive in and learn about Glide in details visit their javadocs and GitHub Wiki.

1 comment:

  1. Sometimes it would require changes in the architecture of the software but it always worth it because you are the one who will work with this code.. kit camere supraveghere exterior

    ReplyDelete