L'accesso alla Rete è un'attività molto comune della app Android. Tale operazione è necessariamente condizionata da tempi di latenza più o meno significativi, e deve perciò essere svolta in maniera asincrona, su un thread secondario. Vista l'importanza di tale tipo di operazioni e le necessità di svolgerle correttamente, è stata predisposta una libreria chimata Volley, che cura tutti gli aspetti di accesso alla Rete:
- gestione autonoma delle richieste e connessioni multiple;
- caching delle risposte sia in memoria che su disco;
- varie classi per il supporto dei tipi più comuni di richieste;
- gestione delle priorità;
- strumenti di log, debug e tracciamento delle attività.
Per usare Volley dobbiamo innanzitutto impostare la permission INTERNET
all'interno del file AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET"/>
La libreria può essere ottenuta tramite git:
git clone https://android.googlesource.com/platform/frameworks/volley
per poi essere importata come modulo all'interno di Android Studio. Quest'ultima operazione si può effettuare tramite la voce di menu New > New Module, dove si indicherà di voler importare un progetto Gradle specificando la cartella del materiale scaricato.
Request e RequestQueue
Lavorare con Volley significa, prima di tutto, confrontarsi con due concetti fondamentali: Request e RequestQueue. Il protocollo HTTP come sappiamo è basato sull'interazione tra client e server in termini di richiesta-risposta: con un derivato della classe Request
formuleremo la richiesta (ad esempio, la risorsa che vogliamo leggere) e l'accoderemo nella RequestQueue
.
In pratica non eseguiremo mai la richiesta "immediatamente, ma ci limiteremo ad inserirla in una coda (la RequestQueue
, appunto). Sarà poi Volley ad eseguirla appena possibile, secondo le sue politiche e le condizioni del sistema.
In ogni oggetto Request
, saranno inclusi i riferimenti a due listener: uno derivante da Response.Listener invocato nel caso in cui la richiesta venga svolta con successo; l'altro, ErrorListener, entra in causa in caso di errori. In quest'ultimo listener utilizzeremo un oggetto VolleyError che non è altro che un'eccezione che maschera un errore HTTP.
Volley prevede già alcuni tipi di richiesta per le forme più comuni di comunicazione. Useremo in questo esempio la StringRequest che restituisce, all'interno di una stringa, l'intero contenuto remoto richiesto.
L'esempio
Immaginiamo che ci vengano resi disponibili dei dati in un file CSV, in cui ogni riga contiene i dati di una persona (nome, cognome, età) separati da punto e virgola:
Marroni;Luca;18
Bianchi;Sergio;25
Neri;Silvio;66
Supponiamo inoltre che tale contenuto sia disponibile all'indirizzo web http://www.example.com/persone.csv. Il nostro scopo sarà raccogliere i dati tramite una StringRequest
di Volley ed elaborarli.
Il layout sarà costituito da una ListView
che vedrà al suo interno le informazioni fornite da Volley all'adapter:
definito nel file /res/layout/activity_main.xml
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent"
android:id="@+id/listview"/>
Nel codice del metodo onCreate inizializzeremo layout e adapter, e subito dopo attiveremo Volley:
public class MainActivity extends AppCompatActivity
{
private static final String REMOTE_ADDR="http://www.example.com/people.csv";
private ArrayAdapter<Person> adapter=null;
private RequestQueue mRequestQueue=null;
private ListView listView=null;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
adapter=new ArrayAdapter<Person>(this, R.layout.row,R.id.testo);
listView= (ListView) findViewById(R.id.listview);
listView.setAdapter(adapter);
mRequestQueue= Volley.newRequestQueue(this);
Request<String> request=prepareRequest();
mRequestQueue.add(request);
}
protected Request<String> prepareRequest()
{
StringRequest request=new StringRequest(REMOTE_ADDR, successListener,errorListener);
return request;
}
}
In particolare, per svolgere l'attività di rete:
- viene inizializzata la coda delle richieste con il metodo
Volley.newRequestQueue(this)
; - viene preparata la richiesta invocando il metodo creato da noi,
prepareRequest()
, in cui essenzialmente si istanzia unaStringRequest
alla quale forniremo l'URL del file CSV e i due listener che analizzeremo a breve; - dopo aver creato la richiesta, essa verrà accodata alla
RequestQueue
con il metodoadd
.
Il listener di successo è definito con il seguente codice:
private Response.Listener<String> successListener= new Response.Listener<String>()
{
@Override
public void onResponse(String s)
{
String[] parts=s.split("\\r?\\n");
List<Person> items=new ArrayList<Person>();
for(String line:parts)
{
Person tmp=new Person(line);
items.add(tmp);
}
adapter.addAll(items);
}
};
L'intero contenuto del file sarà passato nella stringa s, come si vede dal debugger:
Il codice visto poco fa effettua la suddivisione della striga (metodo split
) in base ai ritorno a capo. Poi, con un ciclo for
, verrà eseguito il parsing di ogni riga tramite il costruttore della classe Person
:
class Person
{
private String name=null;
private String surname=null;
private int age;
Person(String s)
{
String[] parts=s.split(";");
this.name=parts[0];
this.surname=parts[1];
this.age=Integer.parseInt(parts[2]);
}
Person(String n, String c, int e)
{
this.name=n;
this.surname=c;
age=e;
}
public String toString()
{
return name+" "+surname+" di anni "+age;
}
}
Quello che segue è invece l'ErrorListener
, che contiene un semplice Toast
per notificare l'errore.
private Response.ErrorListener errorListener=new Response.ErrorListener()
{
@Override
public void onErrorResponse(VolleyError err)
{
Toast.makeText(MainActivity.this, "Download ERROR", Toast.LENGTH_SHORT).show();
}
};
Nel seguito della guida approfondiremo ulteriormente l'uso di questa libreria, ma già questo primo esempio ne ha dimostrato le principali doti. Abbiamo lavorato in modalità asincrona senza avere nominato esplicitamente i thread, interagendo con la Rete senza gestire connessioni e leggendo dati remoti senza aprire nessuno stream: tutto ciò è infatti trasparente al programmatore, grazie a Volley.