Android REST клиент, пример? - PullRequest
111 голосов
/ 25 ноября 2011

Даже если эта тема приняла ответ, не стесняйтесь предлагать другие идеи, которые вы используете или нравится


Я встречал эти статьи:

И это привело меня к видео Google I / O 2010 о клиентских приложениях REST

С тех пор я создаю компонент REST в качестве статического компонента в своем классе контроллера приложений.

С этого момента, я думаю, я должен изменить схему. Кто-то отметил, что Google IOSched приложение является отличным примером того, как писать REST-клиенты на Android. Кто-то еще сказал, что этот способ слишком сложен.

Итак, кто-нибудь может показать нам, какова лучшая практика? Коротко и просто.
Приложение IOSched слишком сложно для примера использования.

Ответы [ 6 ]

95 голосов
/ 02 января 2012

РЕДАКТИРОВАТЬ 2 (октябрь 2017):

Это 2017 год. Просто используйте Retrofit. Почти нет причин использовать что-либо еще.

EDIT:

Первоначальный ответ на момент этого редактирования был старше полутора лет. Хотя концепции, представленные в первоначальном ответе, остаются в силе, как указывают другие ответы, в настоящее время существуют библиотеки, которые облегчают эту задачу для вас. Что еще более важно, некоторые из этих библиотек обрабатывают изменения конфигурации устройства для вас.

Оригинальный ответ сохраняется ниже для справки. Но, пожалуйста, найдите время, чтобы изучить некоторые клиентские библиотеки Rest для Android, чтобы убедиться, что они подходят для ваших случаев использования. Ниже приведен список некоторых библиотек, которые я оценил. Это ни в коем случае не является исчерпывающим списком.


Оригинальный ответ:

Представление моего подхода к использованию REST-клиентов на Android. Я не утверждаю, что это лучший вариант :) Кроме того, обратите внимание, что это то, что я придумал в ответ на мое требование. Вам может понадобиться больше слоев / добавить больше сложности, если этого требует ваш вариант использования. Например, у меня вообще нет локального хранилища; потому что мое приложение может терпеть потерю нескольких ответов REST.

Мой подход использует только AsyncTask s под крышками. В моем случае я «вызываю» эти Задачи из моего Activity экземпляра; но чтобы полностью учитывать такие случаи, как поворот экрана, вы можете позвонить им с номера Service или около того.

Я сознательно выбрал сам мой REST-клиент в качестве API. Это означает, что приложению, использующему мой клиент REST, даже не нужно знать фактические URL-адреса REST и используемый формат данных.

У клиента будет 2 слоя:

  1. Верхний уровень. Цель этого уровня - предоставить методы, которые отражают функциональность REST API. Например, у вас может быть один метод Java, соответствующий каждому URL в вашем REST API (или даже два - один для GET и один для POST).
    Это точка входа в клиентский API REST. Это слой, который приложение будет использовать в обычном режиме. Это может быть одиночка, но не обязательно.
    Ответ на вызов REST анализируется этим слоем в POJO и возвращается в приложение.

  2. Это нижний уровень AsyncTask, который использует методы HTTP-клиента для фактического выхода и выполнения этого вызова REST.

Кроме того, я решил использовать механизм обратного вызова для передачи результатов AsyncTask обратно в приложение.

Достаточно текста. Давайте посмотрим код сейчас. Давайте возьмем гипотетический URL REST API - http://myhypotheticalapi.com/user/profile

Верхний слой может выглядеть так:

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

}

Обратите внимание, что приложение не использует JSON или XML (или любой другой формат), возвращаемый API REST напрямую. Вместо этого приложение видит только компонент Profile.

Тогда нижний слой (слой AsyncTask) может выглядеть так:

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

Вот как приложение может использовать API (в Activity или 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
            }
        });

Надеюсь, комментариев достаточно, чтобы объяснить дизайн; но я был бы рад предоставить больше информации.

11 голосов
/ 01 января 2012

«Разработка клиентских REST-приложений для Android» Вирджила Добжански вызвало много дискуссий, поскольку исходный код не был представлен во время сеанса или был предоставлен впоследствии.

Единственная справочная реализация, которую я знаю (пожалуйста, прокомментируйте, если знаетеподробнее) доступен по адресу Datadroid (сессия Google IO упоминается в разделе / ​​presentation).Это библиотека, которую вы можете использовать в своем собственном приложении.

Вторая ссылка запрашивает «лучшую» REST-инфраструктуру, которая подробно обсуждается в стеке потока.Для меня важен размер приложения, за которым следует производительность реализации.

  • Обычно я использую простую реализацию org.json, которая является частью Android начиная с уровня API 1 и поэтому не увеличивает приложениеsize.
  • Для меня очень интересной была информация о производительности парсеров JSON в комментариях: начиная с Android 3.0 Honeycomb, потоковый парсер GSON включен как android.util.JsonReader.К сожалению, комментарии больше не доступны.
  • Spring Android (который я иногда использую) поддерживает Джексона и GSON.Документация Spring Android RestTemplate Module указывает на пример приложения .

Поэтому я придерживаюсь org.json или GSON для более сложных сценариев.Для архитектуры реализации org.json я использую статический класс, который представляет варианты использования сервера (например, findPerson, getPerson).Я вызываю эту функцию из сервиса и использую служебные классы, которые выполняют сопоставление (специфично для проекта) и сетевой ввод-вывод (мой собственный шаблон REST для простого GET или POST).Я стараюсь избегать использования отражения.

7 голосов
/ 15 февраля 2013

Никогда не используйте AsynTask для выполнения сетевого запроса или чего-либо еще, что необходимо сохранить. Асинхронная задача тесно связана с вашей активностью, и если пользователь изменит приложение с момента создания приложения, AsyncTask будет остановлен.

Я предлагаю вам использовать шаблон Service с Intent Service и ResultReceiver. Взгляните на RESTDroid . Это библиотека, которая позволяет асинхронно выполнять любые REST-запросы и уведомлять ваш пользовательский интерфейс с помощью приемников запросов, реализующих шаблон обслуживания Virgil Dobjanschi.

3 голосов
/ 14 июля 2013

Есть еще одна библиотека с гораздо более чистым API и типобезопасными данными.https://github.com/kodart/Httpzoid

Вот простой пример использования

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

Или более сложный с обратными вызовами

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

Это новый, но выглядит многообещающе.

1 голос
/ 09 октября 2014

Отказ от ответственности: я участвую в проекте rest2mobile с открытым исходным кодом

Другой альтернативой REST-клиента является использование rest2mobile .

Подход немного отличается, поскольку он использует конкретные остальные примеры для генерации клиентского кода для службы REST. Код заменяет URL-адрес REST и полезную нагрузку JSON собственными методами Java и POJO. Он также автоматически обрабатывает соединения с сервером, асинхронные вызовы и преобразования POJO в / из JSON.

Обратите внимание, что этот инструмент поставляется в разных вариантах (cli, плагины, поддержка android / ios / js), и вы можете использовать плагин android studio для генерации API непосредственно в вашем приложении.

Весь код можно найти на github здесь .

1 голос
/ 03 февраля 2014

Существует множество библиотек, и я использую эту: https://github.com/nerde/rest-resource. Она была создана мной, и, как вы можете видеть из документации, она намного чище и проще, чем другие. Он не ориентирован на Android, но я использую его, и он работает довольно хорошо.

Поддерживает HTTP Basic Auth. Он выполняет грязную работу по сериализации и десериализации объектов JSON. Он вам понравится, особенно если ваш API подобен Rails.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...