EDIT 2 (Oktober 2017):
Es ist 2017. Verwenden Sie einfach Retrofit. Es gibt fast keinen Grund, etwas anderes zu verwenden.
BEARBEITEN:
Die ursprüngliche Antwort ist zum Zeitpunkt dieser Bearbeitung mehr als anderthalb Jahre alt. Obwohl die in der ursprünglichen Antwort vorgestellten Konzepte immer noch gelten, wie andere Antworten zeigen, gibt es jetzt Bibliotheken, die Ihnen diese Aufgabe erleichtern. Noch wichtiger ist, dass einige dieser Bibliotheken Änderungen an der Gerätekonfiguration für Sie übernehmen.
Die ursprüngliche Antwort wird unten als Referenz aufbewahrt. Nehmen Sie sich aber auch die Zeit, einige der Rest-Client-Bibliotheken für Android zu untersuchen, um festzustellen, ob sie zu Ihren Anwendungsfällen passen. Das Folgende ist eine Liste einiger der Bibliotheken, die ich evaluiert habe. Es ist keineswegs als vollständige Liste gedacht.
Ursprüngliche Antwort:
Ich präsentiere meinen Ansatz, REST-Clients auf Android zu haben. Ich behaupte jedoch nicht, dass es das Beste ist :) Beachten Sie auch, dass ich mir dies als Antwort auf meine Anforderung ausgedacht habe. Möglicherweise müssen Sie mehr Ebenen haben / mehr Komplexität hinzufügen, wenn Ihr Anwendungsfall dies erfordert. Zum Beispiel habe ich überhaupt keinen lokalen Speicher; weil meine App den Verlust einiger REST-Antworten tolerieren kann.
Mein Ansatz verwendet nur AsyncTasks unter der Decke. In meinem Fall "rufe" ich diese Aufgaben von meiner ActivityInstanz aus auf; Um Fälle wie die Bildschirmrotation vollständig zu berücksichtigen, können Sie sie auch von einem Serviceoder einem anderen aus aufrufen .
Ich habe meinen REST-Client selbst bewusst als API ausgewählt. Dies bedeutet, dass die App, die meinen REST-Client verwendet, nicht einmal die tatsächlichen REST-URLs und das verwendete Datenformat kennen muss.
Der Client hätte 2 Schichten:
Oberste Ebene: Der Zweck dieser Ebene besteht darin, Methoden bereitzustellen, die die Funktionalität der REST-API widerspiegeln. Beispielsweise könnten Sie eine Java-Methode haben, die jeder URL in Ihrer REST-API entspricht (oder sogar zwei - eine für GETs und eine für POSTs).
Dies ist der Einstiegspunkt in die REST-Client-API. Dies ist die Ebene, die die App normalerweise verwenden würde. Es könnte ein Singleton sein, aber nicht unbedingt.
Die Antwort des REST-Aufrufs wird von dieser Ebene in ein POJO analysiert und an die App zurückgegeben.
Dies ist die untergeordnete Ebene AsyncTask, die HTTP-Client-Methoden verwendet, um diesen REST-Aufruf tatsächlich auszuführen.
Außerdem habe ich mich für einen Rückrufmechanismus entschieden, um das Ergebnis des AsyncTasks wieder an die App zu übermitteln .
Genug von Text. Sehen wir uns jetzt einen Code an. Nehmen wir eine hypothetische REST-API-URL - http://myhypotheticalapi.com/user/profile
Die oberste Ebene könnte folgendermaßen aussehen:
/**
* 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();
}
Beachten Sie, dass die App nicht JSON oder XML (oder ein anderes Format) verwendet, das von der REST-API direkt zurückgegeben wird. Stattdessen sieht die App nur die Bean Profile.
Dann könnte die untere Ebene (AsyncTask-Ebene) folgendermaßen aussehen:
/**
* 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);
}
So kann eine App die API verwenden (in einem Activityoder 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
}
});
Ich hoffe, die Kommentare reichen aus, um das Design zu erklären. aber ich würde gerne mehr Infos zur Verfügung stellen.