every list item is created in the list adapter’s getView method, and this method is called whenever you scroll the list to see more items. We could use this method to spawn a thread that downloads the image thumbnail because if we were to do it in place then getView would block.
A commonly used kind of thread pool is one that manages a fixed number of threads that execute tasks posted to a shared queue.
First, the movie_item.xml layout because we need an ImageView next to the movie title text view. Second, we need to change the adapter code to trigger the image download whenever getView is called.
movie_item.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="?android:attr/listPreferredItemHeight" android:gravity="center_vertical"> <ImageView android:id="@+id/movie_icon" android:layout_width="50dip" android:layout_height="50dip" android:scaleType="centerCrop"/> <CheckedTextView android:id="@android:id/text1" android:layout_width="0px" android:layout_height="fill_parent" android:layout_weight="0.9" android:gravity="center_vertical" android:paddingLeft="6dip" android:paddingRight="6dip" android:checkMark="?android:attr/listChoiceIndicatorMultiple" /> </LinearLayout>
/** * 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> { private HashMap<Integer,Boolean> movieCollection =new HashMap<Integer,Boolean>();//storing movie state data which is transient 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); //Create new thread pool executor=(ThreadPoolExecutor)Executors.newFixedThreadPool(5); } 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 downloadImageForView(position,imageView); return listItem; } private void downloadImageForView(int position, ImageView imageView){ final Handler handler=new ImageHandler(position,imageView); final String imageUrl=movieIconUrls[position]; //Schedule new download task executor.execute(new Runnable(){ @Override public void run() { // TODO Auto-generated method stub try{ URL url=new URL(imageUrl); Bitmap image=BitmapFactory.decodeStream(url.openStream()); Bundle data=new Bundle(); data.putParcelable("iamge", image); Message message=new Message(); message.setData(data); handler.sendMessage(message); }catch(Exception e){ e.printStackTrace(); } } }); } }
create array file movie_thumbs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="movie_thumbs">
<item>http://ia.media-imdb.com/images/M/MV5BMTg4MDA2MDM5Nl5BMl5BanBnXkFtZTcwOTU5MTQ2Mg@@._V1._CR328,0,1392,1392_SS90_.jpg
</item>
<item>http://ia.media-imdb.com/images/M/MV5BMTI5MzEwMDYxMV5BMl5BanBnXkFtZTYwNzg5NzM2._V1._CR0,0,320,320_SS90_.jpg
</item>
......
<item>http://ia.media-imdb.com/images/M/MV5BMTk4MDk2NDI5Nl5BMl5BanBnXkFtZTcwMDM3MjcwMg@@._V1._CR120,0,481,481_SS90_.jpg
</item>
</string-array>
</resources>
ImageHandler.java defines the code to update the ImageViews:
public class ImageHandler extends Handler { private int position; private ImageView imageView; public ImageHandler(int position, ImageView imageView) { this.position = position; this.imageView = imageView; } @Override public void handleMessage(Message msg){ int forPosition=(Integer)imageView.getTag(); if(forPosition!=this.position){ return; } Bitmap image=msg.getData().getParcelable("image"); imageView.setImageBitmap(image); } }