Если есть задача написать клиент для работы с Restful сервером, не знаю существует ли удобнее и функциональнее бибилотеки, чем Retrofit. Эта открытая бибилиотека от компании Square в основном поддерживается хорошим человеком Jake Wharton.
Раньше приходилось писать свои велисопеды для работы с сервером с использованием HttpUrlConnection, HttpClinet, выделять дополнительные потоки, парсить ответы и потом передавать все в главный поток, при этом все усложнялось разнообразием запросов https, http, post, get и т.д.
Описание API в коде
Начать работать с этой библиотекой очень просто. Берем наше API сервера и используя аннотацию Retrofit, описываем в интерфейсах
public interface GitHubService {
@GET("/users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
Тут мы описываем GET запрос по адресу /users/{user}/repos (общий для всех запросов домен url указывается в другом месте) причем адрес зависит от перменной user, которую мы передадим в метод. @Path("user") мы указываем, что данную перемнную мы используем в url запроса.
Набор Retrofit очень богат и можно реализовать любой запрос. Весь список аннотаций можно посомтреть тут Больше всего времени уходит на описания API и создания POJO классов, но дальше остатеся только вызывать методы и получать ответы от сервера в удобном ввиде.
Можно api разделить на разные интерйесы для удобства использования например: для авторизации, для работы с пользователем и т.д.
Создание сервиса для работы с API
Теперь, чтобы пользоваться нашими API интерфейсом на необходимо создать RestAdapter и сервис
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("garmax.co")
.build();
Тут мы в setEndpoint указываем общую часть URL для всех запросов.
GitHubService apiService = retrofit.create(GitHubService.class);
Передаем класс нашего интерфейса, вот мы и создали сервис для работы с нашим API.
Сервис можно создавтаь в классе Application и получать доступ к нему из любого места через контекст, либо использовать синглетон.
Выполнение запросов
Начиная с версии 2.0 все результаты методов в retrofit оборачиваются в Call. Этот класс хранит в себе все данные запроса, мы можем повторить запрос, при не удачной попытке, либо вызывая метод clone выполнять один и тот же запрос несколько раз. Так же можно отменить запрос в любой момент вызвав метод cancel класса Call. В предыдущих версиях, что бы указать как будет выполнятся запрос синхронно или асинхронно необходимо было по-разному описывать методы, либо метод должен был возвращать не void тип, либо передавать callback для асинхронного выполнения. С помощью нововведения Call мы можем описать один раз метод, но вызывать по-разному в коде:
Синхронное выполнение запроса:
Call<List<Repo>> call = apiService.listRepos("garmax");
List<Repo> list = call.execute().body();
Асинхронное выполнение запроса
Call<List<Repo>> call = apiService.listRepos("garmax");
call.enqueue(new Callback<List<Repo>>() {
@Override
public void onResponse(Response<List<Repo>> response, Retrofit retrofit) {
if (response.isSuccess()) {
// Запрос выполнился успешно
} else {
// Сервер вернул ошибку
}
}
@Override
public void onFailure(Throwable t) {
// Произошла ошибка при выполненни запроса
}
}
Еще один огромный плюс retorfit это то, что он из коробки работает с RxJava
public interface GitHubService {
@GET("/users/{user}/repos")
Observable<List<Repo>> listRepos(@Path("user") String user);
}
Обработка ошибок Тут тоже все замечательно.
При асинхронном выполнении в callback вызывается метод onFailure, подробности можно получить из аргумента Throwable.
В синхронных запросах необходимо перехватывать исключения RetrofitError
try {
List<Repo> list = call.execute().body();
} catch(RetrofitError error) {
// Обрабатываем ошибку
}
Загрузка файла
Так же можно загружать файлы на сервер POST запросом.
Вместе с файлом будем передавать ещё и его описание. Наш интерфейс будет выглядеть так:
@Multipart
@POST("/upload")
Call<UploadFileResponse> upload(@Part("description") RequestBody fileDescription, @Part MultipartBody.Part file);
Дальше в коде вызываем наш метод:
File myFile = ,,,;
RequestBody bodyDescription = RequestBody.create(MediaType.parse("multipart/form-data"), "My file");
RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), myFile);
MultipartBody.Part bodyFile = MultipartBody.Part.createFormData("file", myFile.getName(), requestFile);
apiService.upload(bodyDescription, bodyFile)
Плюсы
- Очень простой и гибкий способ описать API в коде
- Выполнение запросов асинхронно и синхронно
- Совместимость с RxJava
- Кастомизация: можно выбрать разные библиотеки для выполнения запросов и парсинга ответов разных форматов, вплоть до написания своих.
- Простота при обработке ошибок
Минусы
До версии 2 были неудобные моменты, но в новой версии их исправили. Поэтому добавляем retrofit к проекту и наслаждаемся разработкой клиентских приложений.