Richieste HTTP asincrone con AsyncTask

Il miglior modo per effettuare richieste HTTP (ma non solo) in Android è quello di sfruttare thread appositi per evitare di appesantire ulteriormente l'ambiente grafico e limitare l'usabilità dell'applicazione.
Per realizzare richieste sfruttando l'asincronia esposta dalla classe AsyncTask, dobbiamo innanzitutto definire una interfaccia che ci permetterà di scatenare un listener ad hoc nel momento in cui il client riceve la response HTTP. Per la sua realizzazione ci affidiamo ai generics che ci permettono di astrarci completamente dalla tipologia di informazione trattata.

public interface RemoteCallListener<T> {
    public void onRemoteCallComplete(T data);	
}

Il metodo onRemoteCallComplete verrà invocato automaticamente dal task una volta eseguito il suo compito (ovvero quello di effettaure una chiamata HTTP).
Analizziamo ora nel dettaglio la classe AsyncTask. Supponiamo di dover scaricare per esempio un file json contenente una lista di oggetti di tipo Persona. Innanzitutto è necessario definire le nostre entità tramite la classe Persona:

public class Persona {
    private String nome;
    private String cognome;
    private int eta;
 
    //getter & setter
}

Estendiamo ora la classe AsyncTask sfruttando ulteriormente i generics comunicando alla superclasse la tipologia di dato che abbiamo intenzione di trattare:

public class FetchPersonaListTask extends AsyncTask<String, Void, List<Persona>> {
 
    private final static String TAG = FetchPersonaListTask.getClass().getName();
    RemoteCallListener<List<Persona>> listener;
 
    public FetchPersonaListTask(RemoteCallListener<List<Persona>> listener) {
        this.listener = listener;
    }
 
    @Override
    protected List<Persona> doInBackground(String... urls) {
        List<Persona> personaList = new ArrayList<Persona>();
        String url = urls[0];
        HttpClient httpClient = new DefaultHttpClient();
        HttpGet get = new HttpGet(url);
        try {
             HttpResponse response = httpClient.execute(get);
             if(response.getStatusLine().getStatusCode() == 200) {
                 String responseString = EntityUtils.toString(response.getEntity());
                 JSONArray rawPersonaList = new JSONArray(responseString);
                 Persona persona;
                 for(int i = 0; i<rawPersonaList.length(); i++) {
                     //"traduco" da JsonArray a Persona
                     personaList.add(persona);
                 }
            }
        } catch (Exception e) {
            Log.d(TAG, e.getMessage());
        }
        return personaList;
    }
 
    protected void onPostExecute(List<Persona> personaList) {
       listener.onRemoteCallComplete(personaList);
    }
 
}

I dati comunicati alla superclasse AsyncTask sono in questo ordine:

  • Tipologia di oggetto comunicato in fase di esecuzione (nel caso di richieste HTTP saranno String contenenti un url)
  • Tipologia di oggetto per rappresentare il progresso nell'esecuzione della task (nel nostro caso nessuno quindi usiamo l'oggetto Void)
  • Tipologia di oggetto ritornato al listener (nel nostro caso una List<Persona>)

Una volta comunicate queste informazioni è necessario implementare il metodo doInBackground che riceverà come parametri una lista di String (perchè comunicato nel primo parametro dei generics) e si occuperà di effettuare la chiamata HTTP e la conversione da oggetto json ad oggetto java e il metodo onPostExecute che riceverà come parametro una lista di Persona (perchè comunicato nel terzo parametro dei generics) e che si occuperà semplicemente di delegare l'attività ad un RemoteCallListener.

Una volta definite queste classi per sfruttare questo comportamento basterà far implementare alla nostra Activity l'interfaccia RemoteCallListener e invocare il metodo execute all'oggetto FetchPersonaListTask:

public class PersonaListActivity extends Activity implements RemoteCallListener<List<Persona>> {
 
    private FetchChannelListTask task;
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        String url = "...";
        task = new FetchChannelListTask(this);
    	task.execute(url);
    }
 
    @Override
    public void onRemoteCallComplete(List<Persona> personList) {
        Toast.makeText(getApplicationContext(), "Scaricate " + personList.size() + " persone" , Toast.LENGTH_SHORT).show();
    }
 
}

Chiaro, semplice e ben organizzato :)

 
sviluppo/android/http-asynctask.txt · Last modified: 2011/05/10 11:42 (external edit)
 
Except where otherwise noted, content on this wiki is licensed under the following license:CC Attribution-Noncommercial-Share Alike 3.0 Unported
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki