Client REST Android, campione?


115

Anche se questo thread ha accettato la risposta, sentiti libero di proporre altre idee, che usi o ti piacciono


Ho incontrato questi articoli:

E questo mi ha portato a questo video di Google I / O 2010 sulle applicazioni client REST

Da ora, ho creato il componente REST come componente statico nella mia classe del controller dell'applicazione.

D'ora in poi, penso, dovrei cambiare lo schema. Qualcuno ha sottolineato che l' applicazione Google IOSched è un ottimo esempio di come scrivere client REST su Android. Qualcun altro ha detto che questo metodo è troppo complicato.

Qualcuno può quindi mostrarci qual è la migliore pratica? In breve e in modo semplice.
L'applicazione IOSched è troppo complessa per il caso d'uso di esempio.


Ciao, Generalmente sviluppo un pacchetto separato per il servizio web denominato "ws", ho generalizzato la classe denominata "WebServicUtils.java". La classe WebServiceUtils.java dispone di metodi per accedere al servizio Web. Non sono sicuro che la mia tecnica sia la migliore o meno, ma è riutilizzabile ogni volta che copio il mio pacchetto ws nell'applicazione Android, fammi sapere se vuoi saperne di più sulla mia tecnica.
Ketan Parmar

Non credo che il commentatore di YouTube abbia un'alternativa migliore. Dobbiamo lavorare con le API di Android, anche se spesso sono assurdamente complicate e prolisse.
Timmmm

Come nota a margine, Mechanoid, un plug-in eclipse open source per Android può generare client JSON-REST utilizzando un semplice DSL, una guida su come usarlo può essere trovata qui robotoworks.com/mechanoid-plugin/service-client-dsl (Sono l'autore di questo plugin, ci scusiamo per il plug senza vergogna!)
Ian Warwick

Questo potrebbe essere molto utile per le persone che stanno imparando l'implementazione del client REST Android. Presentazione di Dobjanschi trascritta in PDF: drive.google.com/file/d/0B2dn_3573C3RdlVpU2JBWXdSb3c/…
Kay Zed

Risposte:


99

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 AsyncTasks sotto le coperte. Nel mio caso, "chiamo" queste attività dalla mia Activityistanza; ma per tenere pienamente conto di casi come la rotazione dello schermo, potresti scegliere di chiamarli da uno Serviceo 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:

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

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


Mi piace di più questa risposta a causa di esempi di codice piuttosto carino. Grazie
Marek Sebera

1
Probabilmente non vale nulla, questo non segue davvero un modello MVC RESTful corretto, come descritto da Virgil Dobjanschi. Dovresti incorporare un livello ContentProvider completo, che utilizza un database SQLite che l'app utilizza direttamente. Altrimenti, questo è un client REST buono e leggero per Android.
Cooper

1
Una piccola cosa, dovrai chiamare l'esecuzione su quei Get / PostTask
Mo Kargas

1
Questo è davvero fantastico. Come renderei GetResponseCallback più generico, in modo che non restituisca solo un profilo o suggeriresti di creare un GetResponseCallback separato per ogni tipo di dati dall'API?

1
@MichaelHerbig Sì, ci sono modi per renderli GetResponseCallbackpiù generici. Quello che preferisco è usare un'interfaccia marker : Like interface IGetResopnse{} per denotare tutte le classi che potrebbero essere risposte. Poi, ho class Profile implements IGetResponseecc Infine, fanno GetResponseCallbackgenerico con IGetResponseil limite superiore : public abstract class GetResponseCallback<? extends IGetResponse>.
curioustechizen

11

"Lo sviluppo di applicazioni client REST per Android" di Virgil Dobjanschi ha portato a molte discussioni, dal momento che nessun codice sorgente è stato presentato durante la sessione o fornito in seguito.

L'unica implementazione di riferimento che conosco (per favore commenta se ne sai di più) è disponibile su Datadroid (la sessione di Google IO è menzionata sotto / presentazione). È una libreria che puoi usare nella tua applicazione.

Il secondo collegamento richiede il framework REST "migliore", che viene discusso molto su stackoverflow. Per me la dimensione dell'applicazione è importante, seguita dalle prestazioni dell'implementazione.

  • Normalmente utilizzo l'implementazione semplice org.json, che fa parte di Android dal livello API 1 e quindi non aumenta le dimensioni dell'applicazione.
  • Per me molto interessante sono state le informazioni trovate sulle prestazioni dei parser JSON nei commenti: a partire da Android 3.0 Honeycomb, il parser di streaming di GSON è incluso come android.util.JsonReader. Purtroppo i commenti non sono più disponibili.
  • Spring Android (che uso a volte) supporta Jackson e GSON. La documentazione del modulo Spring Android RestTemplate punta a un'app di esempio .

Pertanto mi attengo a org.json o GSON per scenari più complessi. Per l'architettura di un'implementazione org.json, sto usando una classe statica che rappresenta i casi d'uso del server (ad esempio findPerson, getPerson). Chiamo questa funzionalità da un servizio e utilizzo classi di utilità che eseguono la mappatura (specifica del progetto) e l'IO di rete (il mio modello REST per GET o POST semplici). Cerco di evitare l'uso della riflessione.


4
Il libro O'Reilly, Programming Android, presenta un'implementazione completa del pattern RESTful MVC di Dobjanschi (capitoli 12-13).
Cooper

Grazie per il suggerimento: ho trovato questa dichiarazione su Amazon: "I capitoli 12 e 13 riguardano i fornitori di contenuti. L'ampio trattamento dei fornitori di contenuti con codice di esempio e un'applicazione di esempio mi ha fornito diversi nuovi approfondimenti su come funziona questa tecnologia e su come può essere utilizzato in situazioni di programmazione reali. Il framework del provider di contenuti per l'archiviazione e il riferimento ai dati utilizzando gli URI è una delle nuove funzionalità del sistema operativo Android. Ottimo lavoro nello spiegare la tecnologia passo dopo passo! "
ChrLipp

2
Il codice è su github.com/bmeike/ProgrammingAndroid2Examples (ma mancano capitoli, li puoi trovare nel codice della prima edizione github.com/bmeike/ProgrammingAndroidExamples )
ChrLipp

Qualcuno è riuscito a far funzionare questo codice su ICS +? Il file delle cose da fare nell'esempio FinchVideo afferma sinteticamente "- Arresti anomali in ICS". Sono rimasto un po 'deluso dopo aver acquistato il libro per scoprire che gli esempi di codice sono rotti ...
eageranalyst

7

Non utilizzare mai AsynTask per eseguire richieste di rete o qualsiasi cosa che debba essere mantenuta. Le attività asincrone sono strettamente legate alla tua attività e se l'utente cambia l'orientamento dello schermo da quando l'app è stata ricreata, AsyncTask verrà interrotto.

Ti suggerisco di utilizzare il pattern Service con Intent Service e ResultReceiver. Dai un'occhiata a RESTDroid . È una libreria che ti consente di eseguire qualsiasi tipo di richiesta REST in modo asincrono e di notificare la tua interfaccia utente con Request Listeners che implementano il modello di servizio di Virgil Dobjanschi.


3

C'è un'altra libreria con API molto più pulite e dati indipendenti dai tipi. https://github.com/kodart/Httpzoid

Ecco un semplice esempio di utilizzo

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

O più complesso con i callback

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();

È nuovo di zecca, ma sembra molto promettente.


Sembra essere in esecuzione su AsyncTask, cosa che non va bene per richieste di lunga durata e passa da un'attività all'altra, perché AsyncTask verrà terminato quando l'attività termina.
Malachiasz

1

Ci sono molte biblioteche là fuori e sto usando questa: https://github.com/nerde/rest-resource . Questo è stato creato da me e, come puoi vedere nella documentazione, è molto più pulito e semplice degli altri. Non è focalizzato su Android, ma lo sto usando e funziona abbastanza bene.

Supporta l'autenticazione di base HTTP. Fa il lavoro sporco di serializzare e deserializzare gli oggetti JSON. Ti piacerà, specialmente se la tua API è simile a Rails.


1

Disclaimer: sono coinvolto nel progetto open source rest2mobile

Un'altra alternativa come client REST è usare rest2mobile .

L'approccio è leggermente diverso in quanto utilizza esempi concreti di rest per generare il codice client per il servizio REST. Il codice sostituisce l'URL REST e i payload JSON con metodi java nativi e POJO. Gestisce inoltre automaticamente le connessioni al server, le chiamate asincrone e le conversioni POJO da / a JSON.

Tieni presente che questo strumento è disponibile in diversi gusti (cli, plug-in, supporto per android / ios / js) e puoi utilizzare il plug- in di Android Studio per generare l'API direttamente nella tua app.

Tutto il codice può essere trovato su GitHub qui .


3
Sostituisci il primo link con il target effettivo invece di pubblicizzare il tuo sito.
Skydan

0

Abbiamo reso open source la nostra libreria client REST asincrona leggera per Android, potresti trovarla utile se hai requisiti minimi e non vuoi gestire tu stesso il multithreading - è molto OK per le comunicazioni di base ma non un client REST completo biblioteca.

Si chiama libRESTfulClient e può essere trovato su GitHub .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.