Android REST client, próbka?

Nawet jeśli ten wątek zaakceptował odpowiedź, możesz zaproponować inne pomysły, używasz lub lubisz


Spotkałem się z tymi artykułami:

I to doprowadziło mnie do tego filmu Google I/O 2010 o aplikacjach klienta REST

Od teraz tworzę Komponent REST jako komponent statyczny w mojej klasie kontrolera aplikacji.

Od teraz, myślę, że powinienem zmienić wzór. ktoś zwrócił uwagę, że Aplikacja Google IOSched to świetna przykład jak pisać klientów REST na Androida. ktoś inny powiedział, że ten sposób jest zbyt skomplikowany.

Czy ktoś może nam pokazać, jaka jest najlepsza praktyka? Krótko i prosto.
Aplikacja IOSched jest zbyt złożona dla próbki przypadek użycia.

Author: Community, 2011-11-25

6 answers

[[11]} edycja 2 (Październik 2017): Jest rok 2017. Po prostu użyj doposażenia. Nie ma prawie żadnego powodu, aby używać czegokolwiek innego.

EDIT:

Oryginalna odpowiedź ma ponad półtora roku w momencie tej edycji. Chociaż koncepcje przedstawione w oryginalnej odpowiedzi nadal utrzymują się, jak wskazują inne odpowiedzi, istnieją teraz biblioteki, które ułatwiają Ci to zadanie. Co ważniejsze, niektóre z tych bibliotek obsługują zmiany konfiguracji urządzeń dla ty.

Oryginalna odpowiedź jest zachowana poniżej w celach informacyjnych. Ale proszę również poświęcić trochę czasu na zbadanie niektórych bibliotek klienta Rest dla Androida, aby sprawdzić, czy pasują do Twoich przypadków użycia. Poniżej znajduje się lista niektórych bibliotek, które oceniłem. W żadnym wypadku nie jest to lista wyczerpująca.


Oryginalna Odpowiedź:

Przedstawiam moje podejście do posiadania klientów REST na Androidzie. Nie twierdzę jednak, że jest najlepszy :) zauważ również, że to jest to, co wymyśliłem w odpowiedzi na moje wymagania. Być może trzeba będzie mieć więcej warstw/dodać więcej złożoności, jeśli wymaga tego przypadek użycia. Na przykład nie mam w ogóle pamięci lokalnej; ponieważ moja aplikacja może tolerować utratę kilka odpowiedzi.

Moje podejście wykorzystuje tylko AsyncTasks pod kołdrą. W moim przypadku "wywołuję" te zadania z mojej instancji Activity; ale aby w pełni uwzględnić przypadki takie jak rotacja ekranu, możesz wybrać wywołanie ich z Service lub takiego.

Świadomie wybrałem mojego klienta REST jako API. Oznacza to, że aplikacja, która korzysta z mojego klienta REST, nie musi być nawet świadoma rzeczywistego adresu URL REST i używanego formatu danych.

Klient miałby 2 warstwy:

  1. Górna warstwa: celem tej warstwy jest dostarczenie metod odzwierciedlających funkcjonalność REST API. Na przykład, możesz mieć jedną metodę Java odpowiadającą każdemu adresowi URL w REST API (lub nawet dwie - jedna dla Get i jedna dla postów).
    Jest to punkt wejścia do interfejsu API klienta REST. Jest to warstwa, której aplikacja używałaby normalnie. To może być singleton, ale niekoniecznie.
    Odpowiedź wywołania REST jest parsowana przez tę warstwę do POJO i wrócił do aplikacji.

  2. Jest to warstwa niższego poziomu AsyncTask, która używa metod klienta HTTP, aby faktycznie wyjść i wykonać to wywołanie REST.

Dodatkowo, zdecydowałem się użyć mechanizmu Callback, aby przekazać wynik AsyncTask S z powrotem do aplikacji.

Dość tekstu. Zobaczmy teraz jakiś kod. Przyjmijmy hipotetyczny adres URL REST API- http://myhypotheticalapi.com/user/profile

Górna warstwa może wyglądać to:

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

}

Zauważ, że aplikacja nie używa JSON lub XML (lub jakiegokolwiek innego formatu) zwracanego bezpośrednio przez REST API. Zamiast tego aplikacja widzi tylko fasolę Profile.

Wtedy dolna warstwa (warstwa AsyncTask) może wyglądać tak:

/**
 * 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);
    }

Oto jak aplikacja może korzystać z API (w Activity lub 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
            }
        });

Mam nadzieję, że komentarze są wystarczające, aby wyjaśnić projekt; ale z przyjemnością podam więcej informacji.

 92
Author: curioustechizen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-26 10:00:34

"Tworzenie aplikacji klienckich systemu Android" autorstwa Virgila Dobjanschiego wywołało wiele dyskusji, ponieważ żaden kod źródłowy nie został zaprezentowany podczas sesji ani nie został dostarczony później.

Jedyna implementacja referencyjna, jaką znam (proszę o komentarz, jeśli wiesz więcej) jest dostępna na Datadroid (sesja Google IO jest wymieniona w sekcji / prezentacja). Jest to biblioteka, z której możesz korzystać we własnej aplikacji.

Drugi link pyta o" najlepszy " framework odpoczynku, czyli omówione w dużej mierze na stackoverflow. Dla mnie ważny jest rozmiar aplikacji, a następnie wykonanie wdrożenia.

Dlatego trzymam się org.json lub GSON dla scenariuszy kompleksowych. Dla architektury org.implementacja json, używam statycznej klasy, która reprezentuje przypadki użycia serwera (np. findPerson, getPerson). Nazywam tę funkcjonalność z serwisu i użyj klas narzędzi, które robią mapowanie (specyficzne dla projektu) i sieci IO (mój własny szablon REST dla zwykłego GET lub POST). Staram się unikać użycia refleksji.

 10
Author: ChrLipp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-23 08:06:58

Nigdy nie używaj AsynTask do wykonywania żądań sieciowych lub czegokolwiek, co musi być utrzymywane. Zadania asynchroniczne są silnie powiązane z Twoją aktywnością, a jeśli użytkownik zmieni orientację ekranu, ponieważ aplikacja jest ponownie utworzona, zadanie asynchroniczne zostanie zatrzymane.

Proponuję użyć Service pattern z Intent Service i ResultReceiver. Spójrz na RESTDroid . Jest to biblioteka, która umożliwia asynchronicznie wykonywanie każdego rodzaju żądania REST i powiadamianie interfejsu użytkownika o żądaniach słuchaczy realizacja wzorca usługowego.

 6
Author: Pcriulan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-15 13:12:45

Istnieje inna biblioteka z dużo czystszym API i danymi bezpiecznymi dla typów. https://github.com/kodart/Httpzoid

Oto prosty przykład użycia

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

Lub bardziej złożone z wywołań zwrotnych

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();
Jest świeży, ale wygląda bardzo obiecująco.
 3
Author: Arthur,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-14 05:45:34

Jest mnóstwo bibliotek, a ja używam tej: https://github.com/nerde/rest-resource . to zostało stworzone przeze mnie i, jak widać w dokumentacji, jest o wiele czystsze i prostsze niż pozostałe. Nie jest skupiony na Androidzie, ale używam w nim i działa całkiem dobrze.

Obsługuje HTTP Basic Auth. Wykonuje brudną robotę serializacji i deserializacji obiektów JSON. Spodoba ci się, szczególnie jeśli Twoje API jest podobne do Railsów.

 1
Author: Diego,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-03 01:48:00

Zastrzeżenie: jestem zaangażowany w projekt open source rest2mobile

Inną alternatywą jako klienta REST jest użycie rest2mobile .

Podejście jest nieco inne, ponieważ wykorzystuje konkretne przykłady rest do generowania kodu klienta dla usługi REST. Kod zastępuje REST URL i JSON payloads natywnymi metodami java i Pojo. Automatycznie obsługuje również połączenia z serwerem, asynchroniczne wywołania i konwersje POJO do / Z JSON.

Zauważ, że to narzędzie jest w różnych smakach (cli, wtyczki, android / iOS / js wsparcie) i można użyć android studio plugin do generowania API bezpośrednio do aplikacji.

Cały kod można znaleźć na github tutaj .

 1
Author: Manu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-09 06:03:52