Download Images by AsyncTask in ListView Android Example

On June 15, 2013, in Android, by James Liu

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.

Download and Try Download Images In AsyncTask Android Example
chart


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:

package com.jms.loadimagewithasynctask;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.widget.ListView;

public class MainActivity extends Activity {

	private String[] imageURLArray = new String[]{
			"http://farm8.staticflickr.com/7315/9046944633_881f24c4fa_s.jpg",
			"http://farm4.staticflickr.com/3777/9049174610_bf51be8a07_s.jpg",
			"http://farm8.staticflickr.com/7324/9046946887_d96a28376c_s.jpg",
			"http://farm3.staticflickr.com/2828/9046946983_923887b17d_s.jpg",
			"http://farm4.staticflickr.com/3810/9046947167_3a51fffa0b_s.jpg",
			"http://farm4.staticflickr.com/3773/9049175264_b0ea30fa75_s.jpg",
			"http://farm4.staticflickr.com/3781/9046945893_f27db35c7e_s.jpg",
			"http://farm6.staticflickr.com/5344/9049177018_4621cb63db_s.jpg",
			"http://farm8.staticflickr.com/7307/9046947621_67e0394f7b_s.jpg",
			"http://farm6.staticflickr.com/5457/9046948185_3be564ac10_s.jpg",
			"http://farm4.staticflickr.com/3752/9046946459_a41fbfe614_s.jpg",
			"http://farm8.staticflickr.com/7403/9046946715_85f13b91e5_s.jpg",
			"http://farm8.staticflickr.com/7315/9046944633_881f24c4fa_s.jpg",
			"http://farm4.staticflickr.com/3777/9049174610_bf51be8a07_s.jpg",
			"http://farm8.staticflickr.com/7324/9046946887_d96a28376c_s.jpg",
			"http://farm3.staticflickr.com/2828/9046946983_923887b17d_s.jpg",
			"http://farm4.staticflickr.com/3810/9046947167_3a51fffa0b_s.jpg",
			"http://farm4.staticflickr.com/3773/9049175264_b0ea30fa75_s.jpg",
			"http://farm4.staticflickr.com/3781/9046945893_f27db35c7e_s.jpg",
			"http://farm6.staticflickr.com/5344/9049177018_4621cb63db_s.jpg",
			"http://farm8.staticflickr.com/7307/9046947621_67e0394f7b_s.jpg",
			"http://farm6.staticflickr.com/5457/9046948185_3be564ac10_s.jpg",
			"http://farm4.staticflickr.com/3752/9046946459_a41fbfe614_s.jpg",
			"http://farm8.staticflickr.com/7403/9046946715_85f13b91e5_s.jpg"};
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		
		ListView listView = (ListView)this.findViewById(R.id.listView);
		ImageAdapter imageAdapter = new ImageAdapter(this, R.layout.imageitem, imageURLArray);
		listView.setAdapter(imageAdapter);
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

}

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.

package com.jms.loadimagewithasynctask;

import java.io.IOException;
import java.net.URL;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;

public class ImageAdapter extends ArrayAdapter<String> {
	private String[] imageURLArray;
	private LayoutInflater inflater;

	public ImageAdapter(Context context, int textViewResourceId,
			String[] imageArray) {
		super(context, textViewResourceId, imageArray);
		// TODO Auto-generated constructor stub

		inflater = ((Activity)context).getLayoutInflater();
		imageURLArray = imageArray;
	}

	private static class ViewHolder {
		ImageView imageView;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		// TODO Auto-generated method stub
		ViewHolder viewHolder = null;
		if(convertView == null) {
			convertView = inflater.inflate(R.layout.imageitem, null);

			viewHolder = new ViewHolder();
			viewHolder.imageView = (ImageView)convertView.findViewById(R.id.testImage);
			convertView.setTag(viewHolder);
		}

		viewHolder = (ViewHolder)convertView.getTag();
		
		//load image directly
		Bitmap imageBitmap = null;
		try {
			URL imageURL = new URL(imageURLArray[position]);
            imageBitmap = BitmapFactory.decodeStream(imageURL.openStream());
			viewHolder.imageView.setImageBitmap(imageBitmap);
		} catch (IOException e) {
			// TODO: handle exception
			Log.e("error", "Downloading Image Failed");
			viewHolder.imageView.setImageResource(R.drawable.postthumb_loading);
		}
		
		return convertView;
	}
}

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:

	private class DownloadAsyncTask extends AsyncTask<ViewHolder, Void, ViewHolder> {

		@Override
		protected ViewHolder doInBackground(ViewHolder... params) {
			// TODO Auto-generated method stub
			//load image directly
			ViewHolder viewHolder = params[0];
			try {
				URL imageURL = new URL(viewHolder.imageURL);
				viewHolder.bitmap = BitmapFactory.decodeStream(imageURL.openStream());
			} catch (IOException e) {
				// TODO: handle exception
				Log.e("error", "Downloading Image Failed");
				viewHolder.bitmap = null;
			}
			
			return viewHolder;
		}
		
		@Override
		protected void onPostExecute(ViewHolder result) {
			// TODO Auto-generated method stub
			if (result.bitmap == null) {
				result.imageView.setImageResource(R.drawable.postthumb_loading);
			} else {
				result.imageView.setImageBitmap(result.bitmap);
			}
		}
	}

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:

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		// TODO Auto-generated method stub
		ViewHolder viewHolder = null;
		if(convertView == null) {
			convertView = inflater.inflate(R.layout.imageitem, null);

			viewHolder = new ViewHolder();
			viewHolder.imageView = (ImageView)convertView.findViewById(R.id.testImage);
			convertView.setTag(viewHolder);
		}

		viewHolder = (ViewHolder)convertView.getTag();
		viewHolder.imageURL = imageURLArray[position];
		new DownloadAsyncTask().execute(viewHolder);
		return convertView;
	}

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.

Here you can download this example .apk file and install it on your device.

device-2013-06-15-205022

Get Example Source Code at $0.99



You will get whole “Downloading Images by AsyncTask in ListView” Android source code at $0.99. With this source code, you can do everything you want:

  • Load your own images from your server;
  • Monetize the app with your own AdMob publish id;
  • Use the source code in your own project;
  • Publish this app in your android develop account;
Tagged with:  

44 Responses to “Download Images by AsyncTask in ListView Android Example”

  1. Pamir Cevikogullari says:

    Hi, my code works fine but there is a problem. When I scroll the list view a new images appers which are downloaded from url but when I scrool back, the images download again. It is like refreshing the images. How can I solve it?

    • James says:

      Hi Pamir,

      Because of the performance, ViewList will reuse the View which is used in hidden list row. Therefore, there maybe only 5 Views existing to serve the whole ViewList. And you will see that images are refreshed.

      In my example, there is no cache mechanism. I think the http request may cache the image. To make it more efficient, it’s better to cache the images which is downloaded. Then, we don’t need to load image from internet everytime.

      I think I will update my example later to support the local cache.

      Thanks

  2. tomayyyy says:

    Any suggestions for changable url? I mean e.g: http://www.example.com/content/changable/img/ ???

  3. Andrea says:

    Hi James,
    I’ve bought this source code but I’ve a question: where can I put this code in the Rss feed reader example?

    Because I’m doing a feed reader with your code but I need to download the images indicated in the feed. How can I do this?

    Thanks for all

    Andrea

    • James says:

      In RSS Reader, you have to build an data array to store that images. After that, you can apply this code inside. In my tutorial and tips, I aim to solve one problem at a time. I am not suppose to help solve a project.

      Thanks.

  4. Elia says:

    Hi,
    I bought the sample source, but does not contain the part relating to Google AD.
    I need the complete source code.

  5. Sapi says:

    Hi, where come from “imageitem” ?

  6. Srikanth says:

    Hi,

    I have bought the code and also installed the apk in my SAMSUNG mobile, I could see all the wallpapers, but I could not download any of them. When I click on each image, nothing is happening

  7. priya says:

    thankyou…! its really useful for me

  8. Salim says:

    Hi, firstly thank you very much this tutorial. I get an error like this “Downloading Image Failed” can you help me about it?

  9. venkat says:

    private class DownloadAsyncTask extends AsyncTask
    asking create class ??

  10. venkat says:

    private class DownloadAsyncTask extends AsyncTask

    here ViewHolder showing error and asking to create class

    • James Liu says:

      Then you need to create the ViewHolder class. BTW, in my source code example, I already show the ViewHolder source code there.

  11. venkat says:

    i’m trying to load 21 images from my Json data its loading fine, but when scrolling images are changing why??

  12. siri says:

    Using private for DownloadAsyncTask showing error ??

    • James Liu says:

      Please check it carefully before you report the error. The source code is working properly for others.

  13. Chiru says:

    hello sir, can you tell me how to set onclickListener for those images ?

  14. pullarao says:

    Images are downloading,But when i am scrolling images are downloading again..plz help me in this issue
    Thanks inadvance

    • James Liu says:

      Hi, one question, what do you mean “when you are scrolling images are downloading again”? Can you please describe your problem more clearly?

  15. Gonzalo Infante says:

    I think your code is prone to errors due to possible configuration changes (like orientation) recreating the activity, so the viewholders keep pointing to the old images, as well as leaking them.
    This behavior could be tested (haven’t tested it myself) when scrolling on a slow connection device and rotating the device.

  16. James Liu says:

    I think after you make some configuration changes, like orientation, the app will recreating the activity. But this is not the reason why the viewholders keep pointing to the old images.

    For ListView in Android, it will only create the necessary number of itemview to fit the space. When you scroll the ListView, it will re-use the old itemview for the new row. So you will see the old image in the new row.

    To avoid the app downloading the images all the time, you can implement some cache mechanism. So the refresh speed will be fast.

    For advanced usage, please check this two post:

    Show Image In Listview
    Android Save And Load Downloading File Locally

  17. Giorgi says:

    in DownloadAsyncTask class cannot resolve symbols:
    imageURL and bitmap on viewHolder object..

    btw the ViewHolder Class don’t have a bitmap field..

    any clarification?

    • James Liu says:

      You need to update the ViewHolder class according to your needs. Or you can get the full source code.

  18. Roy says:

    hi James

    i just bought the sample source, and that work very well,
    thank u.
    where at the source code i should write the onclickListener for each image.
    thanks in adnavce

  19. Tony says:

    Awesome link. working perfectly

  20. manoj says:

    Hi
    nice tutorial
    but i’m having one issue i want to set name or some label also in listview correspond to image but in that case images keeps getting downloading and row are changes ..
    so how to set name or label corrospond that image…

    Thanks
    manoj

Leave a Reply

WordPress主题

WordPress主题