EDIT 2 (ottobre 2017):
È il 2017. Usa semplicemente Retrofit. Non c'è quasi alcun motivo per usare qualcos'altro.
MODIFICARE:
La risposta originale risale a più di un anno e mezzo al momento di questa modifica. Sebbene i concetti presentati nella risposta originale valgano ancora, come sottolineano altre risposte, ora ci sono biblioteche là fuori che rendono questo compito più facile per te. Ancora più importante, alcune di queste librerie gestiscono le modifiche alla configurazione del dispositivo per te.
La risposta originale viene mantenuta di seguito per riferimento. Ma ti preghiamo anche di esaminare alcune delle librerie client Rest per Android per vedere se si adattano ai tuoi casi d'uso. Di seguito è riportato un elenco di alcune delle librerie che ho valutato. Non intende in alcun modo essere un elenco esaustivo.
Risposta originale:
Presentazione del mio approccio per avere client REST su Android. Non pretendo che sia il migliore però :) Inoltre, nota che questo è ciò che ho escogitato in risposta alla mia richiesta. Potrebbe essere necessario disporre di più livelli / aggiungere più complessità se il caso d'uso lo richiede. Ad esempio, non ho affatto un archivio locale; perché la mia app può tollerare la perdita di alcune risposte REST.
Il mio approccio utilizza solo AsyncTask
s sotto le coperte. Nel mio caso, "chiamo" queste attività dalla mia Activity
istanza; ma per tenere pienamente conto di casi come la rotazione dello schermo, potresti scegliere di chiamarli da uno Service
o simili.
Ho scelto consapevolmente il mio client REST stesso come API. Ciò significa che l'app che utilizza il mio client REST non deve nemmeno essere a conoscenza dell'URL REST effettivo e del formato dei dati utilizzato.
Il cliente avrebbe 2 livelli:
Livello superiore: lo scopo di questo livello è fornire metodi che rispecchiano la funzionalità dell'API REST. Ad esempio, potresti avere un metodo Java corrispondente a ogni URL nella tua API REST (o anche due: uno per GET e uno per POST).
Questo è il punto di ingresso nell'API del client REST. Questo è il livello che l'app userebbe normalmente. Potrebbe essere un singleton, ma non necessariamente.
La risposta della chiamata REST viene analizzata da questo livello in un POJO e restituita all'app.
Questo è il livello di livello inferiore AsyncTask
, che utilizza i metodi client HTTP per uscire effettivamente ed effettuare quella chiamata REST.
Inoltre, ho scelto di utilizzare un meccanismo di richiamata per comunicare il risultato dei messaggi di posta AsyncTask
elettronica all'app.
Basta con il testo. Vediamo ora un po 'di codice. Prendiamo un ipotetico URL dell'API REST: http://myhypotheticalapi.com/user/profile
Lo strato superiore potrebbe essere simile a questo:
/**
* Entry point into the API.
*/
public class HypotheticalApi{
public static HypotheticalApi getInstance(){
//Choose an appropriate creation strategy.
}
/**
* Request a User Profile from the REST server.
* @param userName The user name for which the profile is to be requested.
* @param callback Callback to execute when the profile is available.
*/
public void getUserProfile(String userName, final GetResponseCallback callback){
String restUrl = Utils.constructRestUrlForProfile(userName);
new GetTask(restUrl, new RestTaskCallback (){
@Override
public void onTaskComplete(String response){
Profile profile = Utils.parseResponseAsProfile(response);
callback.onDataReceived(profile);
}
}).execute();
}
/**
* Submit a user profile to the server.
* @param profile The profile to submit
* @param callback The callback to execute when submission status is available.
*/
public void postUserProfile(Profile profile, final PostCallback callback){
String restUrl = Utils.constructRestUrlForProfile(profile);
String requestBody = Utils.serializeProfileAsString(profile);
new PostTask(restUrl, requestBody, new RestTaskCallback(){
public void onTaskComplete(String response){
callback.onPostSuccess();
}
}).execute();
}
}
/**
* Class definition for a callback to be invoked when the response data for the
* GET call is available.
*/
public abstract class GetResponseCallback{
/**
* Called when the response data for the REST call is ready. <br/>
* This method is guaranteed to execute on the UI thread.
*
* @param profile The {@code Profile} that was received from the server.
*/
abstract void onDataReceived(Profile profile);
/*
* Additional methods like onPreGet() or onFailure() can be added with default implementations.
* This is why this has been made and abstract class rather than Interface.
*/
}
/**
*
* Class definition for a callback to be invoked when the response for the data
* submission is available.
*
*/
public abstract class PostCallback{
/**
* Called when a POST success response is received. <br/>
* This method is guaranteed to execute on the UI thread.
*/
public abstract void onPostSuccess();
}
Tieni presente che l'app non utilizza JSON o XML (o qualsiasi altro formato) restituito direttamente dall'API REST. Invece, l'app vede solo il fagiolo Profile
.
Quindi, il livello inferiore (livello AsyncTask) potrebbe essere simile a questo:
/**
* An AsyncTask implementation for performing GETs on the Hypothetical REST APIs.
*/
public class GetTask extends AsyncTask<String, String, String>{
private String mRestUrl;
private RestTaskCallback mCallback;
/**
* Creates a new instance of GetTask with the specified URL and callback.
*
* @param restUrl The URL for the REST API.
* @param callback The callback to be invoked when the HTTP request
* completes.
*
*/
public GetTask(String restUrl, RestTaskCallback callback){
this.mRestUrl = restUrl;
this.mCallback = callback;
}
@Override
protected String doInBackground(String... params) {
String response = null;
//Use HTTP Client APIs to make the call.
//Return the HTTP Response body here.
return response;
}
@Override
protected void onPostExecute(String result) {
mCallback.onTaskComplete(result);
super.onPostExecute(result);
}
}
/**
* An AsyncTask implementation for performing POSTs on the Hypothetical REST APIs.
*/
public class PostTask extends AsyncTask<String, String, String>{
private String mRestUrl;
private RestTaskCallback mCallback;
private String mRequestBody;
/**
* Creates a new instance of PostTask with the specified URL, callback, and
* request body.
*
* @param restUrl The URL for the REST API.
* @param callback The callback to be invoked when the HTTP request
* completes.
* @param requestBody The body of the POST request.
*
*/
public PostTask(String restUrl, String requestBody, RestTaskCallback callback){
this.mRestUrl = restUrl;
this.mRequestBody = requestBody;
this.mCallback = callback;
}
@Override
protected String doInBackground(String... arg0) {
//Use HTTP client API's to do the POST
//Return response.
}
@Override
protected void onPostExecute(String result) {
mCallback.onTaskComplete(result);
super.onPostExecute(result);
}
}
/**
* Class definition for a callback to be invoked when the HTTP request
* representing the REST API Call completes.
*/
public abstract class RestTaskCallback{
/**
* Called when the HTTP request completes.
*
* @param result The result of the HTTP request.
*/
public abstract void onTaskComplete(String result);
}
Ecco come un'app potrebbe utilizzare l'API (in un Activity
or Service
):
HypotheticalApi myApi = HypotheticalApi.getInstance();
myApi.getUserProfile("techie.curious", new GetResponseCallback() {
@Override
void onDataReceived(Profile profile) {
//Use the profile to display it on screen, etc.
}
});
Profile newProfile = new Profile();
myApi.postUserProfile(newProfile, new PostCallback() {
@Override
public void onPostSuccess() {
//Display Success
}
});
Spero che i commenti siano sufficienti per spiegare il design; ma sarei lieto di fornire maggiori informazioni.