T#020 – Download asincrono di immagini in una ListView con cwac-thumbnail

Nel precedente tutorial abbiamo visto come eseguire il download di una immagine in una ListView, alla fine del post abbiamo promesso di mostrare come utilizzare una libreria esterna che permetta di gestire il download asincrono delle immagini. Nel mondo java le librerie open source sono tantissime, Android essendo abbastanza “giovane” ha un numero di librerie minore, ma comunque ne esistono molte degne di nota.

La libreria che introduciamo oggi in realtà è composta da più jar che fanno parte delle librerie sviluppate da Mark Murphy (potete trovarle tutte su github). Mark Murphy è uno dei guru di Android, scrive libri, sviluppa librerie ed è molto attivo su stack overflow. Parleremo di cwac-thumbnail.

Questa libreria fa proprio quello che ci serve: il download asincrono di immagini in una ListView.

Per poterla utilizzare abbiamo bisogno di includere anche cwac-AdapterWrapper, cwac-Bus, cwac-Cache e cwac-Task, potete trovare tutti i jar necessari per questo esempio in questo zip. Una volta scaricato, scompattatelo dentro una cartella libs creata all’interno del vostro progetto Android. Per utilizzare questi jar dovete aggiungerli al classpath del progetto, per fare ciò nel menù contestuale del progetto selezionate Build Path -> Configure Build Path e nel dialog che compare aggiungete i jar nel tab libraries.

Activity principale

Negli esempi dei post precedenti abbiamo sempre creato un’activity che estende ListActivity, in questo caso usiamo ThumbnailActivity come classe base. Questa classe agevola lo sviluppo di una activity che contiene una ListView con immagini da scaricare in modo asincrono. L’unico metodo da implementare è getImageIdArray che deve ritornare un array con gli id delle ImageView contenute in una riga che devono essere scaricate in modo asincrono. Nel nostro caso questo metodo ritorna un array con un solo elemento:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class MainActivity extends ThumbnailActivity
{
	@Override
	public void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
 
		final ArrayAdapter<Tweet> adapter = new AdapterWithImageAsync(this);
		setListAdapter(adapter);
 
		new DownloadTweetAsyncTask(adapter, (ThumbnailAdapter) getListAdapter()).execute();
	}
 
	@Override
	protected int[] getImageIdArray()
	{
		return new int[]
		{ R.id.image };
	}
}

Questa activity fa poco, in pratica imposta l’adapter e fa partire un task asincrono per il download degli item da twitter. Da notare che usiamo setListAdapter per impostare il nostro adapter ma che successivamente chiamiamo getListAdapter che ci ritornerà un oggetto di tipo ThumbnailAdapter.

La classe ThumbnailAdapter è il fulcro di tutta la libreria: si occupa di effettuare il download asincrono delle immagini e di popolare le righe della lista. Nel nostro caso la passiamo all’oggetto AsyncTask che, nel metodo onProgressUpdate, si occupa di aggiungere i tweet nell’adapter e di chiamare il metodo notifyDataSetChanged per aggiornare l’interfaccia (purtroppo questo metodo va chiamato a mano sul thumbnailAdapter):

1
2
3
4
5
6
7
8
9
@Override
protected void onProgressUpdate(Tweet... values)
{
	for (Tweet tweet : values)
	{
		adapter.add(tweet);
	}
	thumbnailAdapter.notifyDataSetChanged();
}

A questo punto non ci resta che modificare il metodo getView del nostro adapter. Impostiamo quindi l’url dell’immagine da scaricare usando setTag e settiamo a null l’immagine corrente per non avere problemi con il riuso delle righe della lista:

1
2
3
4
5
6
7
8
9
public View getView(int position, View convertView, ViewGroup parent)
{
	convertView = super.getView(position, convertView, parent);
	Tweet t = getItem(position);
	ImageView image = (ImageView) convertView.findViewById(R.id.image);
	image.setTag(t.getProfileImageUrl());
	image.setImageDrawable(null);
	return convertView;
}

Conclusioni

Finito! Non dobbiamo fare altro! La classe ThumbnailAdapter della libreria si occuperà di prendere il valore del campo tag, far partire un thread in background per il download dell’immagine e controllare alla fine del download che la cella sia ancora “valida” (ovvero che sia visibile e che non sia stata riusata per altri item).

Inoltre usando questa libreria viene creata anche una cache delle immagini, nel caso in cui due righe abbiano la stessa immagine questa viene scaricata una volta sola. La cache serve anche nel caso in cui tutte le righe abbiano immagini diverse, nel caso di scroll in alto e in basso ripetuto l’immagine di una riga venga scaricata solo la prima volta e non ogni volta che la riga diventa visibile.

Come sempre il progetto di Eclipse con l’esempio completo è disponibile per il download. La libreria vista in questo post è solo una di quelle scritte da Mark Murphy, vi suggerisco di controllare spesso il suo utente su github per trovare altre librerie altrettanto utili!

By Fabio Collini

Da agosto 2009 sono un freelance android developer, ho rilasciato due applicazioni nell'Android Market: Apps Organizer e Folder Organizer. Presso OmniaGroup ricopro il ruolo di Tech Leader nell'ambito di un progetto di rich internet application che utilizza JSF, JPA(EclipseLink) ed EJB3.

6 comments

  1. Complimenti per le guide e i tutorial, sono favolosi. In una giornata sono riuscito a creare un’app per iPhone seguendo solamente i vostri tutorial. Ora però ho un problema, la stessa app la devo fare android, ma non come fare alcune funzioni. Quindi, non sapendo dove poter chiedere, chiedo aiuto qui. Volevo sapere come qual è la funzione per richiamare l’applicazione delle mappe e la funzione di chiamata. Ovvero, dovrei fare un app dove quando l’utente spinge un tasto, si deve aprire l’applicazione delle mappe di android e mostrare un certo indirizzo, mentre se l’utente spinge un altro tasto allora deve partire una telefonata a un numero preimpostato. E’ possibile?

  2. Ciao, complimenti per il tutorial, davvero ben fatto. Adesso sto provando a impostare il listener di questa listview ma purtroppo non mi riesce, non è che potresti darmi qualche suggerimento? Grazie mille in anticipo!

  3. ciao, ho qualche problema ad inserire le librerie nel path.. anche inserendole non riesce a trovarle. idee?

    1. Ciao, ho risolto la mia precedente domanda (mancavano alcuni file) Ma nel caso in cui volessi personalizzare la view della classe dove compare la lista? Come potrei fare?
      grazie

  4. Ciao, ho risolto la mia precedente domanda (mancavano alcuni file) Ma nel caso in cui volessi personalizzare la view della classe dove compare la lista? Come potrei fare?
    grazie

  5. Salve grazie e complimenti per l’ ottimo tutorial, ma volevo sapere due cosette:
    – 1: sarebbe possibile fare il tutto senza utilizzare questa libreria?
    tipo aggiungendo una activity principale che contiene una listview… o in un altro modo?
    – 2: ho cercato di mettere una progress bar ma non riesco a capire come fare a mettere un contesto e quale contesto mettere…
    Spero in una risposta…

Comments are closed.