Android REST Client, Beispiel?

115

Auch wenn dieser Thread die Antwort akzeptiert hat, können Sie gerne andere Ideen vorschlagen, die Sie verwenden oder mögen


Ich habe diese Artikel getroffen:

Und das führte mich zu diesem Google I / O 2010-Video über REST-Clientanwendungen

Seitdem erstelle ich eine REST-Komponente als statische Komponente in meiner Application Controller-Klasse.

Von jetzt an denke ich, ich sollte das Muster ändern. Jemand wies darauf hin, dass die Google IOSched- Anwendung ein großartiges Beispiel für das Schreiben von REST-Clients auf Android ist. Jemand anderes hat gesagt, dass dieser Weg zu kompliziert ist.

Kann uns bitte jemand zeigen, was die beste Vorgehensweise ist? Kurz und einfach.
Die IOSched-Anwendung ist für einen Beispielanwendungsfall zu komplex.

Marek Sebera
quelle
Hallo, im Allgemeinen entwickle ich ein separates Paket für den Webdienst mit dem Namen "ws". Ich habe die Klasse "WebServicUtils.java" verallgemeinert. Die WebServiceUtils.java-Klasse verfügt über Methoden für den Zugriff auf den Webdienst. Ich bin nicht sicher, ob meine Technik die beste ist oder nicht, aber sie kann jedes Mal wiederverwendet werden, wenn ich mein ws-Paket in die Android-Anwendung kopiere. Lassen Sie mich wissen, wenn Sie mehr über meine Technik erfahren möchten.
Ketan Parmar
Ich denke nicht, dass der Youtube-Kommentator eine bessere Alternative hat. Wir müssen innerhalb der Android-APIs arbeiten, auch wenn diese oft wahnsinnig überkompliziert und wortreich sind.
Timmmm
Nebenbei bemerkt, Mechanoid, ein Open-Source-Eclipse-Plugin für Android, kann JSON-REST-Clients mit einem einfachen DSL generieren. Eine Anleitung zur Verwendung finden Sie hier robotoworks.com/mechanoid-plugin/service-client-dsl (Ich bin der Autor dieses Plugins, Entschuldigung für den schamlosen Plug!)
Ian Warwick
Dies kann sehr hilfreich sein, wenn Sie die Implementierung des Android REST-Clients lernen. Dobjanschis Präsentation wurde in ein PDF übertragen: drive.google.com/file/d/0B2dn_3573C3RdlVpU2JBWXdSb3c/…
Kay Zed

Antworten:

99

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:

  1. 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.

  2. 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.

neugieriger Techizen
quelle
Ich mag diese Antwort eher aufgrund von Beispielen für recht schönen Code. Vielen Dank
Marek Sebera
1
Wahrscheinlich nichts wert, folgt dies nicht wirklich einem richtigen RESTful MVC-Muster, wie es von Virgil Dobjanschi beschrieben wurde. Sie müssten eine vollständige ContentProvider-Ebene einbinden, die eine SQLite-Datenbank verwendet, die die App direkt verwendet. Ansonsten ist dies ein guter, leichter REST-Client für Android.
Cooper
1
Eine kleine Sache, müssen Sie Execute auf diesen Get / PostTask's
Mo Kargas
1
Das ist wirklich toll. Wie würde ich GetResponseCallback allgemeiner gestalten, damit nicht nur ein Profil zurückgegeben wird, oder würden Sie vorschlagen, für jeden Datentyp aus der API ein separates GetResponseCallback zu erstellen?
1
@ MichaelHerbig Ja, es gibt Möglichkeiten, GetResponseCallbackgenerischer zu machen . Ich bevorzuge die Verwendung einer Markierungsschnittstelle : interface IGetResopnse{} Bezeichne gerne alle Klassen, die Antworten sein könnten. Dann, ich habe class Profile implements IGetResponseusw. Schließlich macht GetResponseCallbackgenerisch IGetResponseals die obere Grenze : public abstract class GetResponseCallback<? extends IGetResponse>.
neugieriger Techizen
11

"Entwickeln von Android REST-Client-Anwendungen" von Virgil Dobjanschi führte zu vielen Diskussionen, da während der Sitzung kein Quellcode präsentiert oder danach bereitgestellt wurde.

Die einzige mir bekannte Referenzimplementierung (bitte kommentieren Sie, wenn Sie mehr wissen) ist bei Datadroid verfügbar (die Google IO-Sitzung wird unter / Präsentation erwähnt). Es ist eine Bibliothek, die Sie in Ihrer eigenen Anwendung verwenden können.

Der zweite Link fragt nach dem "besten" REST-Framework, das im Stackoverflow ausführlich diskutiert wird. Für mich ist die Anwendungsgröße wichtig, gefolgt von der Leistung der Implementierung.

  • Normalerweise verwende ich die einfache org.json-Implementierung, die seit API-Level 1 Teil von Android ist und daher die Anwendungsgröße nicht erhöht.
  • Für mich waren die Informationen zur Leistung von JSON-Parsern in den Kommentaren sehr interessant : Ab Android 3.0 Honeycomb ist der Streaming-Parser von GSON als android.util.JsonReader enthalten. Leider sind die Kommentare nicht mehr verfügbar.
  • Spring Android (das ich manchmal benutze) unterstützt Jackson und GSON. Die Dokumentation zum Spring Android RestTemplate-Modul verweist auf eine Beispiel-App .

Deshalb halte ich mich für komplexere Szenarien an org.json oder GSON. Für die Architektur einer org.json-Implementierung verwende ich eine statische Klasse, die die Anwendungsfälle des Servers darstellt (z. B. findPerson, getPerson). Ich rufe diese Funktionalität von einem Dienst auf und verwende Dienstprogrammklassen, die das Mapping (projektspezifisch) und die Netzwerk-E / A (meine eigene REST-Vorlage für einfaches GET oder POST) ausführen. Ich versuche, die Verwendung von Reflexion zu vermeiden.

ChrLipp
quelle
4
Das O'Reilly-Buch Programming Android enthält eine vollständige Implementierung des RESTful MVC-Musters von Dobjanschi (Kapitel 12-13).
Cooper
Vielen Dank für den Hinweis: Ich habe diese Aussage bei Amazon gefunden: "Kapitel 12 und 13 befassen sich mit Inhaltsanbietern. Die umfassende Behandlung von Inhaltsanbietern mit Beispielcode und einer Beispielanwendung gab mir mehrere neue Einblicke in die Funktionsweise und Funktionsweise dieser Technologie in realen Programmiersituationen verwendet werden. Das Content-Provider-Framework zum Speichern und Referenzieren von Daten mithilfe von URIs ist eine der neuartigen Funktionen des Android-Betriebssystems. Großartige Arbeit bei der schrittweisen Erklärung der Technologie! "
ChrLipp
2
Der Code befindet sich auf github.com/bmeike/ProgrammingAndroid2Examples (aber Kapitel fehlen, Sie finden sie im Code der ersten Ausgabe github.com/bmeike/ProgrammingAndroidExamples )
ChrLipp
Hat jemand diesen Code auf ICS + zum Laufen gebracht? In der ToDo-Datei unter dem FinchVideo-Beispiel wird kurz "- Abstürze unter ICS" angegeben. Ich war etwas enttäuscht, nachdem ich das Buch gekauft hatte, um
festzustellen
7

Verwenden Sie niemals AsynTask, um Netzwerkanforderungen auszuführen oder was auch immer beibehalten werden muss. Async-Aufgaben sind stark an Ihre Aktivität gebunden. Wenn der Benutzer die Ausrichtung des Bildschirms ändert, seit die App neu erstellt wurde, wird die AsyncTask gestoppt.

Ich empfehle Ihnen, das Dienstmuster mit Intent Service und ResultReceiver zu verwenden. Schauen Sie sich RESTDroid an . Es ist eine Bibliothek, mit der Sie jede Art von REST-Anforderung asynchron ausführen und Ihre Benutzeroberfläche mit Anforderungslistenern benachrichtigen können, die das Dienstmuster von Virgil Dobjanschi implementieren.

Pierre Criulanscy
quelle
3

Es gibt eine weitere Bibliothek mit einer viel saubereren API und typsicheren Daten. https://github.com/kodart/Httpzoid

Hier ist ein einfaches Anwendungsbeispiel

Http http = HttpFactory.create(context);
http.post("http://example.com/users")
    .data(new User("John"))
    .execute();

Oder komplexer mit Rückrufen

Http http = HttpFactory.create(context);
http.post("http://example.com/users")
    .data(new User("John"))
    .handler(new ResponseHandler<Void>() {
        @Override
        public void success(Void ignore, HttpResponse response) {
        }

        @Override
        public void error(String message, HttpResponse response) {
        }

        @Override
        public void failure(NetworkError error) {
        }

        @Override
        public void complete() {
        }
    }).execute();

Es ist frisch neu, sieht aber sehr vielversprechend aus.

Arthur
quelle
Es scheint auf AsyncTask zu laufen, was für lange laufende Anforderungen und das Wechseln zwischen Aktivitäten nicht gut ist, da AsyncTask beim Beenden von Activity beendet wird.
Malachiasz
1

Es gibt viele Bibliotheken und ich benutze diese: https://github.com/nerde/rest-resource . Dies wurde von mir erstellt und ist, wie Sie in der Dokumentation sehen können, viel sauberer und einfacher als die anderen. Es ist nicht auf Android fokussiert, aber ich benutze es und es funktioniert ziemlich gut.

Es unterstützt HTTP Basic Auth. Es erledigt den schmutzigen Job des Serialisierens und Deserialisierens von JSON-Objekten. Sie werden es mögen, besonders wenn Ihre API Rails-ähnlich ist.

Diego
quelle
1

Haftungsausschluss: Ich bin am Open Source-Projekt rest2mobile beteiligt

Eine andere Alternative als REST-Client ist die Verwendung von rest2mobile .

Der Ansatz unterscheidet sich geringfügig, da konkrete Restbeispiele zum Generieren des Clientcodes für den REST-Service verwendet werden. Der Code ersetzt die REST-URL- und JSON-Nutzdaten durch native Java-Methoden und POJOs. Außerdem werden Serververbindungen, asynchrone Aufrufe und POJO-zu / von JSON-Konvertierungen automatisch verarbeitet.

Beachten Sie, dass dieses Tool in verschiedenen Geschmacksrichtungen (cli, Plugins, android / ios / js - Unterstützung) und Sie können die Verwendung Android Studio Plugin die API direkt in Ihre Anwendung zu generieren.

Den gesamten Code finden Sie hier auf github .

Manu
quelle
3
Bitte ersetzen Sie den ersten Link durch das tatsächliche Ziel, anstatt Ihre Website zu bewerben.
Skydan
0

Wir haben unsere leichtgewichtige asynchrone REST-Client-Bibliothek für Android als Open-Source-Version bereitgestellt. Sie finden sie möglicherweise nützlich, wenn Sie nur minimale Anforderungen haben und das Multithreading nicht selbst ausführen möchten. Für die grundlegende Kommunikation ist dies sehr in Ordnung, aber kein vollständiger REST-Client Bibliothek.

Es heißt libRESTfulClient und ist auf GitHub zu finden .

bk138
quelle