Даже если этот поток принял ответ, не стесняйтесь предлагать другие идеи, вы используете или как
Я встречал эти статьи:
И это привело меня к этому видеообъявлению Google I/O 2010 о клиентских приложениях REST
С тех пор я создаю компонент REST как статический компонент в классе контроллера приложений.
С этого момента, я думаю, я должен изменить шаблон. Кто-то указал, что Приложение Google IOSched - отличный пример того, как писать клиенты REST на Android. Кто-то еще сказал, что эти способы слишком сложны.
Итак, может ли кто-нибудь, пожалуйста, показать нам, что является лучшей практикой? Короче и просто.
Приложение IOSched слишком сложное для примера использования.
Это 2017. Просто используйте Retrofit. Почти нет причин использовать что-либо еще.
Оригинальный ответ более чем на полтораста лет во время этого редактирования. Хотя концепции, представленные в первоначальном ответе, по-прежнему сохраняются, как указывают другие ответы, теперь есть библиотеки, которые облегчают задачу для вас. Что еще более важно, некоторые из этих библиотек обрабатывают изменения конфигурации устройства для вас.
Оригинальный ответ приведен ниже для справки. Но, пожалуйста, также найдите время, чтобы изучить некоторые из клиентских библиотек Rest для Android, чтобы узнать, соответствуют ли они вашим прецедентам. Ниже приведен список некоторых из библиотек, которые я оценил. Он ни в коем случае не должен быть исчерпывающим списком.
Представление моего подхода к тому, чтобы клиенты REST на Android. Я не утверждаю, что это самое лучшее, хотя:) Также обратите внимание, что это то, что я придумал в ответ на мои требования. Возможно, вам понадобится больше слоев/добавьте больше сложностей, если это потребует ваш вариант использования. Например, у меня нет локального хранилища; потому что мое приложение может терпеть потерю нескольких ответов REST.
Мой подход использует только AsyncTask
под обложками. В моем случае я "вызываю" эти задачи из моего экземпляра Activity
; но для полного учета таких случаев, как поворот экрана, вы можете называть их из Service
или таких.
Я сознательно выбрал самого клиента REST как API. Это означает, что приложение, использующее мой клиент REST, даже не должно знать о реальном URL REST и используемом формате данных.
Клиент будет иметь 2 слоя:
Верхний слой: целью этого слоя является предоставление методов, которые отражают функциональность REST API. Например, у вас может быть один метод Java, соответствующий каждому URL-адресу в вашем REST API (или даже два - один для GET и один для POST).
Это точка входа в API клиента REST. Это слой, который приложение будет использовать нормально. Это может быть синглтон, но не обязательно.
Ответ вызова REST обрабатывается этим слоем в POJO и возвращается в приложение.
Это уровень ниже уровня AsyncTask
, который использует методы HTTP-клиента для фактического выхода и выполнения этого вызова REST.
Кроме того, я решил использовать механизм обратного вызова для передачи результата AsyncTask
обратно в приложение.
Достаточно текста. Теперь посмотрим на некоторый код. Возьмем гипотетический URL-адрес API REST - 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 напрямую. Вместо этого приложение видит только bean 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 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
}
});
Я надеюсь, что комментариев достаточно, чтобы объяснить дизайн; но я был бы рад предоставить дополнительную информацию.
"Разработка клиентских приложений REST для Android" Вирджила Добжански привела к большому дискуссиям, поскольку исходный код не был представлен во время сеанса или был предоставлен впоследствии.
Единственная эталонная реализация, которую я знаю (прокомментируйте, если вы знаете больше) доступна в Datadroid (сеанс Google IO упоминается в/презентации). Это библиотека, которую вы можете использовать в своем приложении.
Вторая ссылка запрашивает "наилучшую" структуру REST, которая в значительной степени обсуждается в stackoverflow. Для меня важна размер приложения, за которым следует производительность реализации.
Поэтому я придерживаюсь org.json или GSON для сложных сценариев. Для архитектуры реализации org.json я использую статический класс, который представляет примеры использования сервера (например, findPerson, getPerson). Я вызываю эту функцию из службы и использую классы служебных программ, которые выполняют сопоставление (конкретный проект) и сетевой IO (мой собственный шаблон REST для простого GET или POST). Я стараюсь избегать использования рефлексии.
Никогда не используйте AsynTask для выполнения сетевого запроса или того, что необходимо сохранить. Задача Async тесно связана с вашей деятельностью, и если пользователь изменит ориентацию экрана с момента создания приложения, AsyncTask будет остановлен.
Я предлагаю вам использовать Service pattern с Intent Service и ResultReceiver. Взгляните на RESTDroid. Это библиотека, которая позволяет вам выполнять любой запрос REST асинхронно и уведомлять свой пользовательский интерфейс с помощью Listen Listers, реализующих шаблон обслуживания Virgil Dobjanschi.
Существует еще одна библиотека с гораздо более чистым 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();
Он новый, но выглядит очень многообещающим.
Отказ от ответственности: я участвую в проекте open2mobile с открытым исходным кодом
Другой альтернативой клиенту REST является использование rest2mobile.
Подход немного отличается, поскольку он использует конкретные примеры отдыха для генерации кода клиента для службы REST. Код заменяет URL-адрес REST и полезные данные JSON на собственные Java-методы и POJO. Он также автоматически обрабатывает соединения с сервером, асинхронные вызовы и POJO в/из конверсий JSON.
Обратите внимание, что этот инструмент поставляется в разных вариантах (cli, plugins, android/ios/js), и вы можете использовать плагин для Android-студии для создания API непосредственно в вашем приложении.
Весь код можно найти на github здесь.
Там много библиотек, и я использую этот: https://github.com/nerde/rest-resource. Это было создано мной, и, как вы можете видеть в документации, оно стало более чистым и простым, чем другие. Он не ориентирован на Android, но я использую его, и он работает очень хорошо.
Он поддерживает HTTP Basic Auth. Он выполняет грязную работу по сериализации и десериализации объектов JSON. Вам понравится, особенно если ваш API - это Rails.