- Retrofit
- Задача первая. POJO
- Задача вторая. Интерфейс
- Аннотации
- @Query
- @Headers
- @Multipart
- @FormUrlEncoded
- Задача третья. Retrofit
- Перехватчики (Interceptors)
- HttpLoggingInterceptor
- RxJava
- Retrofit2 на Android используя Kotlin
- 0. Создание проекта
- 1. Добавление зависимостей
- 2. Добавление data class’ов
- 3. Создание Client
- 4. Работа с Interface
- 5. Common
- 6. Макет
- 7. Adapter
- 8. MainActivity
Retrofit
Многие сайты имеют собственные API для удобного доступа к своим данным. На данный момент самый распространённый вариант — это JSON. Также могут встречаться данные в виде XML и других форматов.
Библиотека Retrofit упрощает взаимодействие с REST API сайта, беря на себя часть рутинной работы.
Авторами библиотеки Retrofit являются разработчики из компании «Square», которые написали множество полезных библиотек, например, Picasso, Okhttp, Otto.
Библиотекой удобно пользоваться для запроса к различным веб-сервисам с командами GET, POST, PUT, DELETE. Может работать в асинхронном режиме, что избавляет от лишнего кода.
В основном вам придётся работать с методами GET и POST. Если вы будет создавать собственный API, то будете использовать и другие команды.
В Retrofit 2.x автоматически подключается библиотека OkHttp и её не нужно прописывать отдельно.
Библиотека может работать с GSON и XML, используя специальные конвертеры, которые следует указать отдельно.
Затем в коде конвертер добавляется с помощью метода addConverterFactory().
Список готовых конвертеров:
- Gson: com.squareup.retrofit2:converter-gson
- Jackson: com.squareup.retrofit2:converter-jackson
- Moshi: com.squareup.retrofit2:converter-moshi
- Protobuf: com.squareup.retrofit2:converter-protobuf
- Wire: com.squareup.retrofit2:converter-wire
- Simple XML: com.squareup.retrofit2:converter-simplexml
- Scalars (primitives, boxed, and String): com.squareup.retrofit2:converter-scalars
Также вы можете создать свой собственный конвертер, реализовав интерфейс на основе абстрактного класса Converter.Factory.
Можно подключить несколько конвертеров (порядок важен).
Если вы хотите изменить формат какого-нибудь JSON-объекта, то это можно сделать с помощью GsonConverterFactory.create():
Базовый URL всегда заканчивается слешем /. Задаётся в методе baseUrl().
Можно указать полный URL в запросе, тогда базовый URL будет проигнорирован:
Для работы с Retrofit понадобятся три класса.
- POJO (Plain Old Java Object) или Model Class — json-ответ от сервера нужно реализовать как модель
- Retrofit — класс для обработки результатов. Ему нужно указать базовый адрес в методе baseUrl()
- Interface — интерфейс для управления адресом, используя команды GET, POST и т.д.
Работу с Retrofit можно разбить на отдельные задачи.
Задача первая. POJO
Задача первая — посмотреть на структуру ответа сайта в виде JSON (или других форматов) и создать на его основе Java-класс в виде POJO.
POJO удобнее создавать с помощью готовых веб-сервисов в автоматическом режиме. Либо можете самостоятельно создать класс, если структура не слишком сложная.
В классе часто используются аннотации. Иногда они необходимы, иногда их можно пропустить. В некоторых случаях аннотации помогают избежать ошибок. Список аннотаций зависит от типа используемого конвертера, их список можно посмотреть в соответствующей документации.
Задача вторая. Интерфейс
Задача вторая — создать интерфейс и указать имя метода. Добавить необходимые параметры, если они требуются.
В интерфейсе задаются команды-запросы для сервера. Команда комбинируется с базовым адресом сайта (baseUrl()) и получается полный путь к странице. Код может быть простым и сложным. Можно посмотреть примеры в документации.
Запросы размещаются в обобщённом классе Call с указанием желаемого типа.
В большинстве случаев вы будете возвращать объект Call с нужным типом, например, Call . Если вас не интересует тип ответа, то можете указать Call .
Здесь также используются аннотации, но уже от самой библиотеки.
С помощью аннотации указываются веб-команды, а затем Java-метод. Для динамических параметров используются фигурные скобки (users/
В самой аннотации используется метод, используемый на сервере, а ниже вы можете указать свой вариант (полезно для соответствия стилю вашего кода.
Аннотации
Аннотация | Описание |
---|---|
@GET() | GET-запрос для базового адреса. Также можно указать параметры в скобках |
@POST() | POST-запрос для базового адреса. Также можно указать параметры в скобках |
@Path | Переменная для замещения конечной точки, например, username подставится в в адресе конечной точки |
@Query | Задаёт имя ключа запроса со значением параметра |
@Body | Используется в POST-вызовах (из Java-объекта в JSON-строку) |
@Header | Задаёт заголовок со значением параметра |
@Headers | Задаёт все заголовки вместе |
@Multipart | Используется при загрузке файлов или изображений |
@FormUrlEncoded | Используется при использовании пары «имя/значение» в POST-запросах |
@FieldMap | Используется при использовании пары «имя/значение» в POST-запросах |
@Url | Для поддержки динамических адресов |
@Query
Аннотация @Query полезна при запросах с параметрами. Допустим, у сайте есть дополнительный параметр к запросу, который выводит список элементов в отсортированном виде: http://example.com/api/v1/products/cats?sort=desc. Это несложный пример и мы можем поместить запрос с параметром в интерфейс без изменений.
Если не требуется управлять сортировкой, то её можно оставить в коде и она будет применяться по умолчанию. Но в нашем запросе есть ещё один параметр, который отвечает за категорию котов (домашние, уличные, породистые), которая может меняться в зависимости от логики приложения. Этот параметр можно снабдить аннотацией и программно управлять в коде.
Сортировку мы оставляем как есть, а категорию перенесли в параметры метода под именем categoryId, снабдив аннотацией, с которой параметр будет обращаться на сервер в составе запроса.
Запрос получится в виде http://example.com/api/v1/products/cats?sort=desc&category=5.
В одном методе можно указать несколько Query-параметров.
Запрос может иметь изменяемые части пути. Посмотрите на один из примеров запроса для GitHub: /users/:username. Вместо :username следует подставлять конкретные имена пользователей (https://api.github.com/users/alexanderklimov). В таких случаях используют фигурные скобки в запросе, в самоме методе через аннотацию @Path указывается имя, которое будет подставляться в путь.
@Headers
Пример аннотации @Headers, которая позволяет указать все заголовки вместе.
@Multipart
Пример аннотации @Multipart при загрузке файлов или картинок:
@FormUrlEncoded
Пример использования аннотации @FormUrlEncoded:
Пример аннотации @Url:
Задача третья. Retrofit
Для синхронного запроса используйте метод Call.execute(), для асинхронного — метод Call.enqueue().
Объект для запроса к серверу создаётся в простейшем случае следующим образом
В итоге мы получили объект Retrofit, содержащий базовый URL и способность преобразовывать JSON-данные с помощью указанного конвертера Gson.
Далее в его методе create() указываем наш класс интерфейса с запросами к сайту.
После этого мы получаем объект Call и вызываем метод enqueue() (для асинхронного вызова) и создаём для него Callback. Запрос будет выполнен в отдельном потоке, а результат придет в Callback в main-потоке.
В результате библиотека Retrofit сделает запрос, получит ответ и производёт разбор ответа, раскладывая по полочкам данные. Вам остаётся только вызывать нужные методы класса-модели для извлечения данных.
Основная часть работы происходит в onResponse(), ошибки выводятся в onFailure() (неправильный адрес сервера, некорректные формат данных, неправильный формат класса-модели и т.п). HTTP-коды сервера (например, 404) не относятся к ошибкам.
Метод onResponse() вызывается всегда, даже если запрос был неуспешным. Класс Response имеет удобный метод isSuccessful() для успешной обработки запроса (коды 200хх). В ошибочных ситуациях вы можете обработать ошибку в методе errorBody() класса ResponseBody.
Другие полезные методы Response.
- code() — HTTP-код ответа
- body() — сам ответ в виде строки, без сериализации
- headers() — HTTP-заголовки
- message() — HTTP-статус (или null)
- raw() — сырой HTTP-ответ
Можно написать такую конструкцию.
Для отмены запроса используется метод Call.cancel().
Перехватчики (Interceptors)
В библиотеку можно внедрить перехватчики для изменения заголовков при помощи класса Interceptor из OkHttp. Сначала следует создать объект перехватчика и передать его в OkHttp, который в свою очередь следует явно подключить в Retrofit.Builder через метод client().
Поддержка перехватчиков/interceptors для обработки заголовков запросов, например, для работы с токенами авторизации в заголовке Authorization.
HttpLoggingInterceptor
Библиотека HttpLoggingInterceptor является частью OkHttp, но поставляется отдельно от неё. Перехватчик следует использовать в том случае, когда вам действительно нужно изучать логи ответов сервера. По сути библиотека является сетевым аналогом привычного LogCat.
Подключаем перехватчик к веб-клиенту. Добавляйте его после других перехватчиков, чтобы ловить все сообщения. Существует несколько уровней перехвата данных: NONE, BASIC, HEADERS, BODY. Последний вариант самый информативный, пользуйтесь им осторожно. При больших потоках данных информация забьёт весь экран. Используйте промежуточные варианты.
RxJava
Сами разработчики библиотеки очень любят реактивное программирование и приложили многие усилия для интеграции с библиотекой RxJava.
Источник
Retrofit2 на Android используя Kotlin
Сегодня мы рассмотрим работу с Retrofit 2. Правды ради стоит отметить, что мы будем работать еще с 2 отдельными библиотеками, а именно Picasso и Spots-dialog.
Это статью я рекомендую к прочтению только для тех, кто еще не работал с Retrofit 2. Ведь в этой статье я буду описывать все максимально подробно, чтобы все поняли.
0. Создание проекта
Здесь все максимально просто, создаем новый проект в Android Studio, выбираем Empty Activity. Далее необходимо выбрать язык программирования, у нас это будет Kotlin.
1. Добавление зависимостей
Сейчас нам нужно добавить все необходимые библиотеки, поэтому мы заходим в build.gradle и добавляем следующие:
Как вы уже могли заметить здесь мы добавили все необходимые библиотеки, в том числе и Spots progress dialog. Более подробно вы можете ознакомится с этим здесь. После чего в build.gradle(Modul:app) мы должны вставить это:
Осталось лишь зайти в manifests и добавить разрешение на использование телефона
2. Добавление data class’ов
Прежде чем перейти к второму пункту нам нужно узнать, а откуда получать данные? Парсить будет отсюда.
Отлично, далее копируем содержимое этого сайта и идем сюда. Сюда мы вставляем ранее скопированный текст с нашего сайта, после того как мы нажали на tree нам выдался список, раскроем его, теперь мы видим, что у нас есть 8 объектов. Если кто-то не понял, то я покажу вам скрин:
То что вы видите справа это наш текст, который мы скопировали, а то что справа, это уже обработанные данные.
Теперь вернемся к Android Studio мы создаем папку называем ее Model там мы создаем kotlin class и называем ее Movie из обычного класса мы преобразуем data class, мы просто перед class добавим data, а фигурные скобки заменяем на круглые, далее в скобках указываем переменные которые мы уже подсмотрели на сайте, кстати переменные должны быть нулабельного типа.
Если вы зададитесь вопросом, а почему папка называется Model, то я вам скажу, что:
Model — это логика, которая связанна с данными приложения. Другими словами это POJO, классы работы с API, базой данных.
3. Создание Client
Далее мы создаем папку Retrofit, а в папке мы создаем object, и называем его RetrofitClient, далее создаем переменную retrofit типа Retrofit, после этого создаем функцию и называем ее getCleint(baseUrl: String) и тип возвращаемого значения Retrofit. В теле функции необходимо выполнить проверку retrofit’a на null и если ретрофит равен null, то мы к ретрофиту присваиваем Retrofit.Builder() присоединяем baseUrl с параметром baseUrl далее присоединяем метод addconverterFactory c параметром GsonConverterFactory.create() и билдим с помощью метода build() и возвращаем ретрофит в ненулевой тип
Builder в Retrofit — это экземпляр, который использует интерфейс и API Builder, чтобы задать определение конечной точки URL для операций HTTP
4. Работа с Interface
Interface — нужен для создания абстрактных классов.
Создаем пакет Interface в него мы кладем Interface и называем RetrofitServieces. Создаем Get запрос в скобках пишем кавычки, а в кавычках указывает ветку с которой будем парсить данные у нас это marvel. Но перед этим стоит сказать что такое GET и POST запрос
GET — запрашивает данные с определенного ресурса(сайта)
POST — отправляет данные на сервер для последующей обработки
Хорошо, теперь нужно создать функцию getMovieList, которая должна будет возвращать Call типа MutableList, a MutableList должен быть типа Movie
5. Common
Сейчас мы должны создать папку Common, в эту папку мы кладем object и называем его Common, создаем переменную, называем ее BASE_URL и в нее мы должны положить ссылку с которой парсим данные, но не класть последнюю ветку, так как именно с нее мы получаем данные. Создаем переменную retrofitServices, у нее есть метод get() к нему мы присваиваем RetrofitClient, а уже потом к RetrofitClient мы сетим метод getClient c параметром RetrofitServices::class.java
6. Макет
Переходим к activity_main.xml и добавляем туда RecyclerView
В папке layout создаем item_layout в root element указываем CardView
7. Adapter
Теперь мы должны создать пакет Adapter, в него мы кладем класс и называем его MyMovieAdapter
Adapter отвечает за извлечение данных из набора данных и за создание объектов View по основе этих данных.
В классе MyMovieAdapter мы создаем переменные, которые будут доступны только в этом классе private val movieList: MutableList типа Movie и указываем тип возвращаемого значения у нас это будет RecyclerView.Adapter типа MyMovieAdapter.MyViewHolder
Имплементируем методы, а именно onCreateViewHolder, getItemCount и onBindViewHolder.
Создаем класс MyViewHolder, в данном класс указываем параметр itemView: View и тип возвращаемого значения RecyclerView.ViewHolder и в тело данного класса мы помещаем переменные, например:
val image:ImageView = itemView.image_movie image_movie у нас тянется из item_layout
и так указываем для всех оставшихся view элементов.
Создам функцию bind c параметром listItem: Movie, здесь мы можем сделать наши view элементы кликабельными, я думаю вы умеете это делать.
Далее мы переделываем getItemCount() в override fun getItemCount() = movieList.size. Здесь все просто, мы создали функцию и возвращаем movieList.size. Отлично, осталось лишь разобраться с onBindViewHolder и onCreateViewHolder
onCreateViewHolder — создает новый объект ViewHolder всякий раз, когда RecyclerView нуждается в этом.
onBindViewHolder — принимает объект ViewHolder и устанавливает необходимые данные для соответствующей строки во view компоненте
Сейчас мы разберем случай c onCreateViewHolder тип возвращаемого значения MyViewHolder.
Создаем переменную itemView присваиваем ей LayoutInflater.from(parent.context).inflate(R.layout.item_layout, parent, false) и возвращаем MyViewHolder с параметром itemView. Теперь переходим к onBindViewHolder в теле мы создаем переменную listItem: Movie и присваиваем movieList[position]. Далее к holder’y мы присоединяем метод bind с параметрами listItem. Далее используем библиотеку Picasso.
Picasso.get().load(movieList[position].imageurl).into(holder.image). После чего добавляем holder.txt_name.text = movieList[position].name, и так мы делаем со всеми нашими view элементами
8. MainActivity
Отлично! Осталось совсем чуть-чуть. Переходим в MainActivity для начала мы создадим переменные, и чтобы не объявлять их типа null объявим их через lateinit var mService: RetrofitServices, нам необходимо создать еще 3 таких, а именно: LinearLayoutManager, MyMovieAdapter, AlertDialog. Вы можете назвать их как хотите, это роли не сыграет. В методе onCreate мы к RetrofitServices присваиваем Common.retrofitServices. На следующей строке к нашему recyclerView мы присоединяем setHasFixedSize(true) — благодаря этому методу мы сможем оптимизировать свой список, после мы к нашему layoutManager присваиваем LinearLayoutManager(this).
Layout Manager — это вещь, которая отвечает позиционирование View компонентов, которые больше не видны пользователю. Далее все также легко к нашему списку присоединяем layoutManager и уже к этому присваиваем layoutManager. Хорошо, теперь работа с библиотекой SpotsDialog. указываем ранее названную переменную с типом AlertDialog присваиваем SpotsDialog присоединяем метод Builder после этого присоединяем метод setCancelablec c параметром true к этому мы должны присоединить метод setContext c параметром this и присоединить метод build.
Теперь мы должны создать новую функцию за пределами метода onCreate назваться функция будет getAllMovieList. В теле этой функции мы должны указать наш dialog и присоединить к нему метод show()
далее к mService добавляем метод getMovieList .enqueue(object: Callback < )
Сейчас нам необходимо имплементировать методы, у нас их две onResponse и onFailure
и в onResponse, а именно в теле данного метода мы к adapter’y присваиваем
далее к adapter’y присваиваем метод notifyDataSetChanged(). К нашему списку мы присоединяем adapter и присваиваем adapter. после к dialog присваиваем метод dismiss(). Это значит то, что наш диалог пропадет после того, как наши данные загрузятся.
Источник