EDIT 2 (outubro de 2017):
Estamos em 2017. Basta usar Retrofit. Quase não há razão para usar qualquer outra coisa.
EDITAR:
A resposta original tinha mais de um ano e meio na época desta edição. Embora os conceitos apresentados na resposta original ainda sejam válidos, como outras respostas apontam, agora existem bibliotecas que tornam essa tarefa mais fácil para você. Mais importante, algumas dessas bibliotecas tratam das mudanças de configuração do dispositivo para você.
A resposta original é mantida abaixo para referência. Mas também reserve um tempo para examinar algumas das bibliotecas cliente Rest para Android para ver se elas se encaixam nos seus casos de uso. A seguir está uma lista de algumas das bibliotecas que avaliei. Não tem a intenção de ser uma lista exaustiva.
Resposta Original:
Apresentando minha abordagem para ter clientes REST no Android. Eu não afirmo que seja o melhor :) Além disso, observe que foi isso que eu criei em resposta à minha solicitação. Pode ser necessário ter mais camadas / adicionar mais complexidade se o seu caso de uso exigir. Por exemplo, eu não tenho armazenamento local; porque meu aplicativo pode tolerar a perda de algumas respostas REST.
Minha abordagem usa apenas AsyncTask
s nos bastidores. No meu caso, eu "chamo" essas tarefas da minha Activity
instância; mas para levar em conta casos como rotação de tela, você pode escolher chamá-los de um Service
ou outro.
Eu escolhi conscientemente meu próprio cliente REST para ser uma API. Isso significa que o aplicativo que usa meu cliente REST nem precisa estar ciente da URL REST real e do formato de dados usado.
O cliente teria 2 camadas:
Camada superior: o objetivo desta camada é fornecer métodos que espelham a funcionalidade da API REST. Por exemplo, você poderia ter um método Java correspondente a cada URL em sua API REST (ou mesmo dois - um para GETs e um para POSTs).
Este é o ponto de entrada para a API do cliente REST. Esta é a camada que o aplicativo usaria normalmente. Pode ser um singleton, mas não necessariamente.
A resposta da chamada REST é analisada por esta camada em um POJO e retornada ao aplicativo.
Esta é a AsyncTask
camada de nível inferior , que usa métodos de cliente HTTP para realmente sair e fazer a chamada REST.
Além disso, optei por usar um mecanismo de retorno de chamada para comunicar o resultado do AsyncTask
s de volta ao aplicativo.
Chega de texto. Vamos ver alguns códigos agora. Vamos pegar um URL de API REST hipotético - http://myhypotheticalapi.com/user/profile
A camada superior pode ter esta aparência:
/**
* 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();
}
Observe que o aplicativo não usa o JSON ou XML (ou qualquer outro formato) retornado pela API REST diretamente. Em vez disso, o aplicativo vê apenas o bean Profile
.
Então, a camada inferior (camada AsyncTask) pode ter a seguinte aparência:
/**
* 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);
}
Veja como um aplicativo pode usar a API (em um 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
}
});
Espero que os comentários sejam suficientes para explicar o design; mas ficaria feliz em fornecer mais informações.