Download Images by AsyncTask in ListView Android Example

Loading images is the most common task for Android apps. Loading image task can be very simple. But if the image size is very big or there are lots of images to be downloaded, it will take a long time. During the downloading progress, all android UI will freeze. Therefore, we have to download images in different thread from main thread (UI thread). In this Android tutorial, I will give an example to show how to use Asynctask to download a list of images.

At the beginning, I will create a ListView. In each row of the list, there are one image from internet. Therefore, we need to download the image in each row view for the list in the ArrayAdapter. For more information about ListView and ArrayAdapter, please check post:ListView and ArrayAdapter.

First, let show the MainActivity.java source code:

01 package com.jms.loadimagewithasynctask;
02
03 import android.app.Activity;
04 import android.os.Bundle;
05 import android.view.Menu;
06 import android.widget.ListView;
07
08 public class MainActivity extends Activity {
09
10     private String[] imageURLArray = new String[]{
11             "http://farm8.staticflickr.com/7315/9046944633_881f24c4fa_s.jpg",
12             "http://farm4.staticflickr.com/3777/9049174610_bf51be8a07_s.jpg",
13             "http://farm8.staticflickr.com/7324/9046946887_d96a28376c_s.jpg",
14             "http://farm3.staticflickr.com/2828/9046946983_923887b17d_s.jpg",
15             "http://farm4.staticflickr.com/3810/9046947167_3a51fffa0b_s.jpg",
16             "http://farm4.staticflickr.com/3773/9049175264_b0ea30fa75_s.jpg",
17             "http://farm4.staticflickr.com/3781/9046945893_f27db35c7e_s.jpg",
18             "http://farm6.staticflickr.com/5344/9049177018_4621cb63db_s.jpg",
19             "http://farm8.staticflickr.com/7307/9046947621_67e0394f7b_s.jpg",
20             "http://farm6.staticflickr.com/5457/9046948185_3be564ac10_s.jpg",
21             "http://farm4.staticflickr.com/3752/9046946459_a41fbfe614_s.jpg",
22             "http://farm8.staticflickr.com/7403/9046946715_85f13b91e5_s.jpg",
23             "http://farm8.staticflickr.com/7315/9046944633_881f24c4fa_s.jpg",
24             "http://farm4.staticflickr.com/3777/9049174610_bf51be8a07_s.jpg",
25             "http://farm8.staticflickr.com/7324/9046946887_d96a28376c_s.jpg",
26             "http://farm3.staticflickr.com/2828/9046946983_923887b17d_s.jpg",
27             "http://farm4.staticflickr.com/3810/9046947167_3a51fffa0b_s.jpg",
28             "http://farm4.staticflickr.com/3773/9049175264_b0ea30fa75_s.jpg",
29             "http://farm4.staticflickr.com/3781/9046945893_f27db35c7e_s.jpg",
30             "http://farm6.staticflickr.com/5344/9049177018_4621cb63db_s.jpg",
31             "http://farm8.staticflickr.com/7307/9046947621_67e0394f7b_s.jpg",
32             "http://farm6.staticflickr.com/5457/9046948185_3be564ac10_s.jpg",
33             "http://farm4.staticflickr.com/3752/9046946459_a41fbfe614_s.jpg",
34             "http://farm8.staticflickr.com/7403/9046946715_85f13b91e5_s.jpg"};
35     @Override
36     protected void onCreate(Bundle savedInstanceState) {
37         super.onCreate(savedInstanceState);
38         setContentView(R.layout.main);
39         
40         ListView listView = (ListView)this.findViewById(R.id.listView);
41         ImageAdapter imageAdapter = new ImageAdapter(this, R.layout.imageitem, imageURLArray);
42         listView.setAdapter(imageAdapter);
43     }
44
45     @Override
46     public boolean onCreateOptionsMenu(Menu menu) {
47         // Inflate the menu; this adds items to the action bar if it is present.
48         getMenuInflater().inflate(R.menu.main, menu);
49         return true;
50     }
51
52 }

In the MainActivity class, we define an array of image url for ListView to download and show. We are using one customized ArrayAdapter to generate the row view for ListView. Now, let’s see the source code of ImageAdapter class.

01 package com.jms.loadimagewithasynctask;
02
03 import java.io.IOException;
04 import java.net.URL;
05
06 import android.app.Activity;
07 import android.content.Context;
08 import android.graphics.Bitmap;
09 import android.graphics.BitmapFactory;
10 import android.util.Log;
11 import android.view.LayoutInflater;
12 import android.view.View;
13 import android.view.ViewGroup;
14 import android.widget.ArrayAdapter;
15 import android.widget.ImageView;
16
17 public class ImageAdapter extends ArrayAdapter<String> {
18     private String[] imageURLArray;
19     private LayoutInflater inflater;
20
21     public ImageAdapter(Context context, int textViewResourceId,
22             String[] imageArray) {
23         super(context, textViewResourceId, imageArray);
24         // TODO Auto-generated constructor stub
25
26         inflater = ((Activity)context).getLayoutInflater();
27         imageURLArray = imageArray;
28     }
29
30     private static class ViewHolder {
31         ImageView imageView;
32     }
33
34     @Override
35     public View getView(int position, View convertView, ViewGroup parent) {
36         // TODO Auto-generated method stub
37         ViewHolder viewHolder = null;
38         if(convertView == null) {
39             convertView = inflater.inflate(R.layout.imageitem, null);
40
41             viewHolder = new ViewHolder();
42             viewHolder.imageView = (ImageView)convertView.findViewById(R.id.testImage);
43             convertView.setTag(viewHolder);
44         }
45
46         viewHolder = (ViewHolder)convertView.getTag();
47         
48         //load image directly
49         Bitmap imageBitmap = null;
50         try {
51             URL imageURL = new URL(imageURLArray[position]);
52             imageBitmap = BitmapFactory.decodeStream(imageURL.openStream());
53             viewHolder.imageView.setImageBitmap(imageBitmap);
54         } catch (IOException e) {
55             // TODO: handle exception
56             Log.e("error", "Downloading Image Failed");
57             viewHolder.imageView.setImageResource(R.drawable.postthumb_loading);
58         }
59         
60         return convertView;
61     }
62 }

Currently, we have finished the basic of the requirement. We create a ListView and show the images in the ListView. However, it is a big problem when you compile and run the app in your devices. The ListView response is horrible slow and sometimes it looks like no response at all when we drag the ListView up and down. That is because we are downloading the image on the main thread or the UI thread. To solve ListView hang problem when downloading the image, we have to move the downloading logic in a different thread.

Download Image in AsyncTask Example

As Android developers guide mentioned, AsyncTask must be subclassed to be used. Therefore, we will create subclass, DownloadAsyncTask, in our ImageAdapter. Once the ListView request a row View from ImageAdapter, we will start a new AsyncTask and download the image in the background. In the DownloadAsyncTask class, we will override the doInBackground method which will be called to start download the image and onPostExecute method which will update our ListView when the image downloading in AsyncTask finished. Here is the subclass of AsyncTask:

01 private class DownloadAsyncTask extends AsyncTask<ViewHolder, Void, ViewHolder> {
02
03     @Override
04     protected ViewHolder doInBackground(ViewHolder... params) {
05         // TODO Auto-generated method stub
06         //load image directly
07         ViewHolder viewHolder = params[0];
08         try {
09             URL imageURL = new URL(viewHolder.imageURL);
10             viewHolder.bitmap = BitmapFactory.decodeStream(imageURL.openStream());
11         } catch (IOException e) {
12             // TODO: handle exception
13             Log.e("error", "Downloading Image Failed");
14             viewHolder.bitmap = null;
15         }
16         
17         return viewHolder;
18     }
19     
20     @Override
21     protected void onPostExecute(ViewHolder result) {
22         // TODO Auto-generated method stub
23         if (result.bitmap == null) {
24             result.imageView.setImageResource(R.drawable.postthumb_loading);
25         } else {
26             result.imageView.setImageBitmap(result.bitmap);
27         }
28     }
29 }

Using AsyncTask to Download Images

As you can see, we move all the image downloading code in AsyncTask now. To instantiate the subclass of AsyncTask and start to download the image, we have to change our getView function a little bit. Instead of loading the image immediately in getView, we create a new AsyncTask class and call AsyncTask.execute every time. Here is the example code:

01 @Override
02 public View getView(int position, View convertView, ViewGroup parent) {
03     // TODO Auto-generated method stub
04     ViewHolder viewHolder = null;
05     if(convertView == null) {
06         convertView = inflater.inflate(R.layout.imageitem, null);
07
08         viewHolder = new ViewHolder();
09         viewHolder.imageView = (ImageView)convertView.findViewById(R.id.testImage);
10         convertView.setTag(viewHolder);
11     }
12
13     viewHolder = (ViewHolder)convertView.getTag();
14     viewHolder.imageURL = imageURLArray[position];
15     new DownloadAsyncTask().execute(viewHolder);
16     return convertView;
17 }

That’s it. Now you can compile and try the new app in your device. The performance is getting much better. The ListView scrolls smoothly and image downloading also works fine. If you still have problems about downloading images in ListView, you can leave the reply and I will answer your questions if I can.

device-2013-06-15-205022

Advertisements

2 comments on “Download Images by AsyncTask in ListView Android Example

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s