Costruire un servizio HTTP

Immaginiamo di voler creare un servizio per Android che effettui il download di un file xml da un sito e notifichi all'utente l'avvenuta ricezione. Un tale esempio può essere sfruttato per moltissime occasioni. Cominciamo dal vedere la struttura minima di un servizio nel seguente codice:
La comunicazione con il server è ovviamente asincrona e la sua gestione è delegata alle due classi interne: il working thread ed il ResponseHandler. Il primo è sempre necessario, poiché si tratta della creazione di un Thread separato dove svolgere il lavoro del service, in modo che non vada ad interferire con il Thread UI dell'utente e sia davvero un servizio. La seconda classe interna, invece, gestisce la risposta dal server.
Sia il working thread che il response handler sono classi interne al servizio e dunque ereditano dal servizio stesso tutte le sue variabili, anche quelle private! L'uso di una classe interna è l'unico caso, nel mondo Java, in cui una classe può essere definita private.
Vediamo ora nello specifico come "riempire" le due classi. Il working thread avrà un codice simile a questo:
In questo esempio ho voluto anche mostrare come spedire un parametro POST al server. Nel caso si vogliano aggiungere più parametri è sufficiente aggiungere valori alla variabile nameValuePairs. Si notino invece la prima e la penultima riga: la prima restituisce un oggetto HttpClient, creato a livello di applicazione e dunque unico per tutte le eventuali istanze del servizio. Si tratta di un piccolo trucco per il risparmio di memoria e risorse del sistema. Con la penultima riga, invece, all'esecuzione del metodo execute, si realizza l'accoppiamento fra il working thread ed il response handler, un po' come avviene nelle comuncazioni AJAX in cui viene indicato quale sia il metodo per gestire la response del server.
Vediamo invece il codice del ResponseHandler:
dove il metodo notifyDownload è dichiarato all'interno del servizio:
Questo tutorial si chiude qui, lasciando il lettore con questo metodo incompiuto. La ragione è che quest'ultimo metodo fa parte della gestione delle notifiche di Android, un argomento che sarà oggetto di un altro articolo.
public class MioServizio extends Service
{
private WorkingThread workingThread;
private final static String LOG_TAG = "LOG_TAG_SERVICE";
protected static final int HTTP_NOTIFICATION_ID = 0;
protected static final String RESPONSE_OK = "OK";
public void onCreate() {
super.onCreate();
workingThread = new WorkingThread();
workingThread.start();
}
public void onDestroy() {
workingThread.setAlive(false);
super.onDestroy();
}
// classe per gestire la risposta asincrona
private final ResponseHandler<String> myResponseHandler = new ResponseHandler<String>() {
....
};
// thread dove effettuare il "lavoro sporco"
private final class WorkingThread extends Thread {
....
}
@Override
public IBinder onBind(Intent intent) { return null; }
} private final class WorkingThread extends Thread {
private final static long SLEEP_TIME = 15000L;
private final static String TARGET_URL = "http://www.miosito.it/pagina.php";
private boolean alive = true;
public void setAlive(boolean alive) { this.alive = alive; }
public void run() {
while (alive) {
try {
// Otteniamo il riferimento al HttpClient attraverso la Application
HttpClient httpClient = ((MiaApplication) getApplication()).getThreadSafeHttpClient();
HttpPost request = new HttpPost(TARGET_URL);
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
nameValuePairs.add(new BasicNameValuePair("parametro", "valore");
httpClient.execute(request, myResponseHandler);
this.sleep(SLEEP_TIME);
} catch (Exception e) {
Log.e(LOG_TAG, e.toString());
} finally { }
}
}
} private final ResponseHandler<String> myResponseHandler = new ResponseHandler<String>() {
@Override
public String handleResponse(HttpResponse response) throws ClientProtocolException, IOException {
InputStream content = response.getEntity().getContent();
byte[] buffer = new byte[1024];
int numRead = 0;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while((numRead=content.read(buffer))!=-1){
baos.write(buffer, 0, numRead);
}
content.close();
FileOutputStream file = new FileOutputStream(new File("/data/data/mio.pacchetto/files/file.xml"));
baos.writeTo(file);
notififyDownload("message");
return "ok";
}
}; private void notififyDownload(String message) {
Message messageToSend = handler.obtainMessage();
messageToSend.obj = message;
handler.sendMessage(messageToSend);
}