AsyncTask offers an easy-to-use (but more limited).
You need to perform an asynchronous job that follows a pre-process/process/postprocess pattern, and are looking for a code template that allows you to report progress
to the user or otherwise update the UI in each step.
In the last technique, we retrieved movie thumbnail images by having a simple downloader helper method fork a new thread that downloaded the image, and then passed it to a custom handler object that updated the image on the list view.
create the AsyncTask class DownloadTask:
public class DownloadTask extends AsyncTask<String,Void,Bitmap> {
private int position;
private ImageView imageView;
private Drawable placeholder;
public DownloadTask(int position,ImageView imageView){
this.position=position;
this.imageView=imageView;
Resources resources=imageView.getContext().getResources();
this.placeholder=resources.getDrawable(android.R.drawable.gallery_thumb);
}
//Called before task runs
protected void onPreExecute(){
imageView.setImageDrawable(placeholder);
}
//task logic
protected Bitmap doInBackground(String... inputUrls) {
try{
URL url=new URL(inputUrls[0]);
return BitmapFactory.decodeStream(url.openStream());
}catch(Exception e){
e.printStackTrace();
return null;
}
}
//called after task runs
protected void onPostExecute(Bitmap result){
int forPosition=(Integer)imageView.getTag();
if(forPosition==this.position){
this.imageView.setImageBitmap(result);
}
}
}
worker arguments (String), worker progress (Void), and worker result (Bitmap).
trigger the task,modify the class MovieAdapter:
/**
* Another perfectly valid approach would be to create a Movie model class.
* get rid of the HashMap.
*/
//The MovieAdapter keeps track of selected movies
//Adapter separating data from its representation on the screen
public class MovieAdapter extends ArrayAdapter<String> {
//storing movie state data
//this state is transient
private HashMap<Integer,Boolean> movieCollection=new HashMap<Integer,Boolean>();
private String[] movieIconUrls;//List of movie image URLs
private ThreadPoolExecutor executor;//Controls thread pool
public MovieAdapter(Context context) {
super(context,R.layout.movie_item,android.R.id.text1,context.getResources().getStringArray(R.array.movies));
// TODO Auto-generated constructor stub
//Read image URLs into array
movieIconUrls=context.getResources().getStringArray(R.array.movie_thumbs);
}
public void toggleMovie(int position){
if(!isInCollection(position)){
movieCollection.put(position, true);
}
else{
movieCollection.put(position, false);
}
}
public boolean isInCollection(int position){
return movieCollection.get(position) == Boolean.TRUE;
}
@Override
//returns the view needed for each item.
//cache and reuse item views via convertView for performance reasons
public View getView(int position,View convertView,ViewGroup parent){
View listItem=super.getView(position, convertView, parent);
CheckedTextView checkMark=(CheckedTextView)listItem.findViewById(android.R.id.text1);
checkMark.setChecked(isInCollection(position));
ImageView imageView =(ImageView)listItem.findViewById(R.id.movie_icon);
imageView.setImageDrawable(null);
imageView.setTag(position);//link position to image view
String imageUrl=movieIconUrls[position];
new DownloadTask(position,imageView).execute(imageUrl);
return listItem;
}
}
first, the absence of any explicit interthread communication using handlers and messages, and second, a higher code quality achieved by having all code related to the download task in a single class.