Клиент Android REST, образец?

115

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


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

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

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

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

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

Марек Себера
источник
Здравствуйте! Обычно я разрабатываю отдельный пакет для веб-службы с именем «ws», у меня есть обобщенный класс с именем «WebServicUtils.java». Класс WebServiceUtils.java имеет методы для доступа к веб-сервису. Я не уверен, что моя техника является лучшей или нет, но ее можно использовать повторно каждый раз, когда я копирую свой пакет ws в приложение для Android. Дайте мне знать, если вы хотите узнать больше о моей технике.
Кетан Пармар
Я не думаю, что у комментатора YouTube есть лучшая альтернатива. Мы должны работать с API Android, даже если они зачастую безумно сложны и многословны.
Timmmm
В качестве примечания: Mechanoid, плагин eclipse с открытым исходным кодом для Android, может генерировать клиентов JSON-REST с помощью простого DSL, руководство по его использованию можно найти здесь robotoworks.com/mechanoid-plugin/service-client-dsl (Я являюсь автором этого плагина, извините за бессовестный плагин!)
Ян Варвик
Это может быть очень полезно для людей, изучающих реализацию клиента Android REST. Презентация Добьянски переведена в PDF-файл: drive.google.com/file/d/0B2dn_3573C3RdlVpU2JBWXdSb3c/…
Кей Зед

Ответы:

99

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

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

РЕДАКТИРОВАТЬ:

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

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


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

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

Мой подход использует просто AsyncTasks под прикрытием. В моем случае я «вызываю» эти Задачи из своего 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.

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

Хватит текста. Давайте теперь посмотрим код. Возьмем гипотетический 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 (или любой другой формат), возвращаемые REST API напрямую. Вместо этого приложение видит только компонент 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
            }
        });

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

curioustechizen
источник
Мне этот ответ больше нравится из-за примеров довольно красивого кода. Спасибо
Марек Себера 06
1
Вероятно, ничего не стоит, это действительно не соответствует правильному шаблону RESTful MVC, как описано Вирджилом Добьянски. Вам нужно будет включить полный уровень ContentProvider, который использует базу данных SQLite, которую приложение напрямую использует. В остальном это хороший легкий клиент REST для Android.
Cooper
1
Одна маленькая вещь, вам нужно будет вызвать execute для этих Get / PostTask
Мо Каргас
1
Это действительно здорово. Как мне сделать GetResponseCallback более универсальным, чтобы он не передавал обратно только профиль, или вы бы предложили создать отдельный GetResponseCallback для каждого типа данных из API?
1
@MichaelHerbig Да, есть способы сделать GetResponseCallbackболее универсальным. Я предпочитаю использовать интерфейс маркера : например, interface IGetResopnse{} обозначать все классы, которые могут быть ответами. Тогда, я и class Profile implements IGetResponseт.д. И, наконец, сделать GetResponseCallbackобщий с IGetResponseкак верхняя граница : public abstract class GetResponseCallback<? extends IGetResponse>.
curioustechizen 08
11

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

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

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

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

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

ChrLipp
источник
4
Книга О'Рейли «Программирование Android» содержит полную реализацию шаблона RESTful MVC Добьянски (главы 12-13).
Cooper
Спасибо за подсказку: я нашел это утверждение на Amazon: «Главы 12 и 13 посвящены поставщикам контента. Подробное рассмотрение поставщиков контента с помощью примеров кода и примеров приложения дало мне несколько новых идей о том, как работает эта технология и как она может можно использовать в реальных ситуациях программирования. Фреймворк поставщика контента для хранения и ссылки на данные с использованием URI - одна из новых функций операционной системы Android. Отличная работа по пошаговому объяснению технологии! "
ChrLipp
2
Код находится на github.com/bmeike/ProgrammingAndroid2Examples (но главы отсутствуют, вы можете найти их в коде первой редакции github.com/bmeike/ProgrammingAndroidExamples )
ChrLipp
Кто-нибудь смог запустить этот код на ICS +? В файле задач в примере FinchVideo кратко сказано: «- Сбои в ICS». После покупки книги я был несколько разочарован, обнаружив, что примеры кода не работают ...
eageranalyst
7

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

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

Пьер Криуланси
источник
3

Есть еще одна библиотека с гораздо более чистым 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();

Он свежий, но выглядит очень многообещающе.

Артур
источник
Кажется, он работает на AsyncTask, что не подходит для длительных запросов и переключения между действиями, потому что AsyncTask будет убит при выходе из Activity.
Malachiasz
1

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

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

Диего
источник
1

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

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

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

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

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

Manu
источник
3
Вместо рекламы своего сайта замените первую ссылку фактической целью.
Skydan
0

У нас есть открытый исходный код нашей легкой асинхронной клиентской библиотеки REST для Android, вы можете найти ее полезной, если у вас минимальные требования и вы не хотите самостоятельно обрабатывать многопоточность - это очень хорошо для базовых коммуникаций, но не для полноценного клиента REST библиотека.

Он называется libRESTfulClient и его можно найти на GitHub .

bk138
источник