EDIT 2 (octobre 2017):
Nous sommes en 2017. Il suffit d'utiliser Retrofit. Il n'y a presque aucune raison d'utiliser autre chose.
ÉDITER:
La réponse originale a plus d'un an et demi au moment de cette modification. Bien que les concepts présentés dans la réponse originale soient toujours valables, comme le soulignent d'autres réponses, il existe désormais des bibliothèques qui vous facilitent la tâche. Plus important encore, certaines de ces bibliothèques gèrent les changements de configuration de périphérique pour vous.
La réponse originale est conservée ci-dessous pour référence. Mais prenez également le temps d'examiner certaines des bibliothèques clientes Rest pour Android pour voir si elles correspondent à vos cas d'utilisation. Voici une liste de certaines des bibliothèques que j'ai évaluées. Il ne s'agit en aucun cas d'une liste exhaustive.
Réponse originale:
Présentation de mon approche pour avoir des clients REST sur Android. Je ne prétends pas que ce soit le meilleur cependant :) Notez également que c'est ce que j'ai proposé en réponse à mon besoin. Vous devrez peut-être avoir plus de couches / ajouter plus de complexité si votre cas d'utilisation l'exige. Par exemple, je n'ai pas du tout de stockage local; car mon application peut tolérer la perte de quelques réponses REST.
Mon approche utilise juste AsyncTask
s sous les couvertures. Dans mon cas, j'appelle ces tâches à partir de mon Activity
instance; mais pour tenir pleinement compte des cas tels que la rotation de l'écran, vous pouvez choisir de les appeler à partir de l'un Service
ou l'autre.
J'ai délibérément choisi mon client REST lui-même comme API. Cela signifie que l'application qui utilise mon client REST n'a même pas besoin de connaître les URL REST réelles et le format de données utilisé.
Le client aurait 2 couches:
Couche supérieure: le but de cette couche est de fournir des méthodes qui reflètent la fonctionnalité de l'API REST. Par exemple, vous pouvez avoir une méthode Java correspondant à chaque URL de votre API REST (ou même deux - une pour les GET et une pour les POST).
Il s'agit du point d'entrée dans l'API client REST. C'est la couche que l'application utiliserait normalement. Cela pourrait être un singleton, mais pas nécessairement.
La réponse de l'appel REST est analysée par cette couche dans un POJO et renvoyée à l'application.
Il s'agit de la AsyncTask
couche de niveau inférieur , qui utilise des méthodes client HTTP pour sortir et effectuer cet appel REST.
De plus, j'ai choisi d'utiliser un mécanisme de rappel pour communiquer le résultat des AsyncTask
s à l'application.
Assez de texte. Voyons maintenant du code. Prenons une URL API REST hypothétique - http://myhypotheticalapi.com/user/profile
La couche supérieure pourrait ressembler à ceci:
/**
* 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();
}
Notez que l'application n'utilise pas le JSON ou XML (ou tout autre format) renvoyé directement par l'API REST. Au lieu de cela, l'application ne voit que le bean Profile
.
Ensuite, la couche inférieure (couche AsyncTask) pourrait ressembler à ceci:
/**
* 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);
}
Voici comment une application peut utiliser l'API (dans un Activity
ou 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
}
});
J'espère que les commentaires sont suffisants pour expliquer le design; mais je serais heureux de fournir plus d'informations.