Guide: How to load images asynchronously into a ListView:

Recently I worked on a ListView that required to load preaty large images into
the ListView view so I encounter the all mighty OutOfMemory exception every
Android developer will encounter some time during his developer live.

So for this topic I have decide to concentrate on the current libraries that allow you
to load images in an asynchronous way into your desired ImageViews in your ListViews:

1. So first I want to talk about the nostra13 / Android-Universal-Image-Loader:

this is a well known library that has been used widely by the Android developers,
I won’t be heavy on code on this one, as I think that his documentation is very sufficient.
The main thing you have to do is to initialize the ImageLoader object in your Application class,
and providing it with a ImageLoaderConfiguration object:

public class MyApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();

        // Create global configuration and initialize ImageLoader with this configuration
        ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getApplicationContext())
            ...
            .build();
        ImageLoader.getInstance().init(config);
    }
}

Check out the link for all the different configurations you can make when building the
ImageLoaderConfiguration class. Next to actually load an image inside your adapter you should use this:

imageLoader.displayImage(imageUri, imageView, displayOptions, new ImageLoadingListener() {
    @Override
    public void onLoadingStarted(String imageUri, View view) {
        ...
    }
    @Override
    public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
        ...
    }
    @Override
    public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
        progress.setVisibility(View.GONE);
    }
    @Override
    public void onLoadingCancelled(String imageUri, View view) {
        ...
    }
});

And use the onLoadingComplete method to preform and action when image
is finished loading like removing a ProgressBar.

2. The next library is newer and is less known among developers Square / Picasso,
You can find the GitHub page here.From my usage I must say that it does a great job
and provide you with some useful methods along side with a fading-in affect when image is finished loading out of the box.

So the deal here is even simpler, to load an image into an ImageView all you have to do is this:

Picasso.with(context).load(url).into(imageView);

If you want a finishing call back it not problem as well:

Picasso.with(context).load(url).into(imageView, new Callback() {
			
    @Override
    public void onSuccess() {
        progress.setVisibility(View.GONE);
    }
			
    @Override
    public void onError() {
        progress.setVisibility(View.GONE); 
    }
);

An option i really liked with this library is a call back you can use before the image
is applied to the ImageView:

target = new Target() {
    @Override
    public void onBitmapLoaded(Bitmap image, LoadedFrom arg1) {
        imageView.setImageBitmap(Util.getCroppedBitmap(image));
    }
	
    @Override
     public void onPrepareLoad(Drawable arg0) {}
				
    @Override
    public void onBitmapFailed(Drawable arg0) {
        imageView.setImageDrawable(context.getResources().getDrawable(R.drawable.person));
    }
};
Picasso.with(context).load(url).into(target);

3. Currently I’m checking the Volley library that was presented to us by Google team at 2013 I/O.
This library is not concentrated only on image loading, but on most of our application network
tasks. By their description it shows great promise. And very soon I will update this post with
my conclusions. You can fork it from here.

UPDATE:
Well after a few day of usage I came to conclusion that for now I will stay away from the Volley
library for loading images and use a more dedicated library for that. The reasons for that will
come later but for now I will explain how to use it. Now to use the Volley library is a little
more difficult then to use the two previously described libraries.

First you will need to change your XML layout file that contains the ImageView you want to
populate with an image and to replace this ImageView with a NetworkImageView like so:

<com.android.volley.toolbox.NetworkImageView
    android:id="@+id/image"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_gravity="center"
    android:adjustViewBounds="true"
    android:scaleType="fitXY" />

Next get the this view using the right casting:

NetworkImageView networkImageView = (NetworkImageView) findViewById(R.id.image);

And finally set the image from the URL:

holder.venueImage.setImageUrl(url, ImageCacheManager.getInstance().getImageLoader());

If you look closely to the last line of code, you will see that the second parameter of the
setImageUrl is an ImageLoader object. I’m supplying it using the ImageCacheManager
object. The reason I do that is because Volley doesn’t provide L2 caching out of the box
and you will need to provide your own implementation for that.

For that purpose I found this blog post very useful as he provides a full working
implementation for you. Just follow the post, you will find there a GitHub repository with
an implementation you can use: Google I/O 2013: Volley Image Cache Tutorial

If you are using this implementation you will need to initialize your ImageCacheManager
in your Application class:

public class App extends Application 
{
    private static int DISK_IMAGECACHE_SIZE = 1024*1024*10;
    private static CompressFormat DISK_IMAGECACHE_COMPRESS_FORMAT = CompressFormat.PNG;
    private static int DISK_IMAGECACHE_QUALITY = 100;  //PNG is lossless so quality is ignored but must be provided

    public void onCreate() 
    {
        super.onCreate();
        init();
    }

    private void init() {
        RequestManager.init(this);
        createImageCache();
    }
	
    /**
     * Create the image cache. Uses Memory Cache by default. Change to Disk for a Disk based LRU implementation.  
     */
    private void createImageCache(){
        ImageCacheManager.getInstance().init(this,
            this.getPackageCodePath()
            , DISK_IMAGECACHE_SIZE
            , DISK_IMAGECACHE_COMPRESS_FORMAT
            , DISK_IMAGECACHE_QUALITY  
            , CacheType.MEMORY);
    }
}

Now the reason that currently I have decided not to use this library is that for some reason
I have found it lacking some basic functionality the two other libraries had. The first problem
is that I didn’t find a way to get a finish call back on loading the image (so I could remove the
progress bar as I did before…). The second problem I encountered is that when you use Volley
in a ListView and you swipe it so fast the image doesn’t has enough time to load, Volley will
stop it’s loading until the next time you will come back to it. I didn’t find a way to change this behavior.

And that’s it for now, stay tuned.

2 Responses to this entry

  • paru Says:

    loading progressbar using ImageLoader is helped me thanks

    Posted on May 30th, 2014 at 1:28 am Reply | Quote
  • Abdul Says:

    Nice post and good efforts done by you. well done and thanks for these great refrences. thanks a lot man

    Posted on October 9th, 2014 at 12:05 pm Reply | Quote

Leave a comment