Rxjava2 retrofit2 android dependencies

RxJava2 + Retrofit 2. Модифицируем адаптер для обработки состояния отсутствия интернета на Android

Довольно часто необходимо делать повторные запросы в сеть, например, когда у пользователя не было интернета и он захотел получить данные из интернета. Неплохо бы было заново кинуть запрос при его появлении. Хорошая практика — показать пользователю определенный UI, который объяснил бы ему что произошло и позволил бы заново кинуть запрос. Добавление такой логики может быть довольно болезненной, особенно, когда у нас огромное множество ViewModel классов. Конечно, можно реализовать логику резапросов в каждом ViewModel классе, но это не удобно и возникает огромная вероятность появления ошибок.

Есть ли способ сделать эту обработку лишь единожды?

К счастью RxJava2 и Retrofit2 позволяют это сделать

На Stackoverflow уже есть несколько решений:

1. Создание собственного CallAdapterFactory (подробнее тут)
2. Повтор цепочки, используя PublishSubject (подробнее тут)

В первом решении используется RxJava1, она уже устарела и так же она просто повторяет цепочку несколько раз, не реагируя, на появление события. Второе решение хорошее, но нам необходимо использовать оператор retryWhen в каждой цепочке. И так, я объединил два решения в одно.

Реализация

Давайте создадим простой проект. Расположим на главном экране две вкладки. На каждой из них отображен текст, который будет показывать сколько элементов загружено по API. Если в ходе выполнения возникнет ошибка, мы отобразим SnackBar с кнопкой Try Again.

Определим такие базовые классы как BaseActivity, BaseFragment, BaseViewModel, они необходимы для реализации логики повторения запроса в одном месте и избегания дублирования этого кода. Создадим два фрагмента, которые будут расширять BaseFragment. Каждый размещенный фрагмент имеет собственный ViewModel и самостоятельно делает запросы к API. Я создал эти фрагменты, чтобы показать, что при возникновении ошибки каждый запрос будет повторен. Затем создадим фабрику RxRetryCallAdapterFactory, которая расширяет CallAdapter.Factory. После этого создадим экземпляр RxJava2CallAdapterFactory. Нам необходим этот экземпляр для получения доступа к RxJava2CallAdapter, так как мы не хотим дублировать код, который уже есть в Retrofit библиотеке. Так же давайте создадим статический метод, который будет возвращать экземпляр нашей фабрики. Пример кода ниже:

Далее, создадим RxRetryCallAdapter, который реализовываем интерфейс CallAdapter и нам необходимо передать экземпляр CallAdapter в конструктор. По факту, это должен быть экземпляр RxJava2CallAdapter, который возвращает исходная фабрика.

Далее нам необходимо реализовать следующие вещи:

  • retryWhen оператор используется для внедрения функционала повторения
  • doOnError() оператор, который обрабатывает ошибки. Он используется для отправки трансляции, которая обрабатывается в BaseActivity и показывает SnackBar пользователю
  • PublishSubject используется как триггер событий, который переподписывает цепочку
  • observeOn(Schedulers.io()) оператор, который необходимо применить к PublishSubject (если не добавить это строку, подписка произойдет в основном потоке и мы получим NetworkOnMainThreadException
  • Трансформируем PublishSubject в Flowable и установим BackpressureStrategy.LATEST, так как нам необходима только последняя ошибка

Заметка: Для предоставления PublishSubject я создал простой синглтон класс, который предоставляет все синглтон зависимости в проекте. В реальном проекте вы, вероятно, будете использовать фреймворк внедрения зависимостей, такой как Dagger2

Когда пользователь кликает по кнопке Try again мы вызываем onNext PublishSubject. После этого мы переподпишемся на цепочку rx.

Тестирование

Отключим интернет и запустим приложение. Количество загруженных элементов равно нулю на каждом вкладке и SnackBar отображает ошибку. Включаем интернет и кликаем на Try Adain. Через несколько секунд количество загруженных элементов изменяется на каждой из вкладок.

Если кому необходимо, то исходники лежат тут

Источник

Retrofit на Android с Kotlin

Одним из самых захватывающих объявлений на Google I/O в этом году стала официальная поддержка Kotlin для разработки под Android.

Котлин на самом деле не новый язык, ему уже >5 лет и он довольно зрелый. Здесь вы можете получить более подробную информацию о языке

Я планирую поделиться некоторыми «практиками» использования Kotlin в разработке Android.

Retrofit — очень популярная библиотека для работы с сетью, и она широко используется в сообществе разработчиков. Даже Google использует его в своих образцах кода.

В этой статье я расскажу о том, как использовать REST API в ваших приложениях с помощью Retrofit + Kotlin + RxJava. Мы будем использовать API Github для получения списка разработчиков Java в Омске, Россия. Также, я затрону некоторые особенности языка программирования и расскажу о том, как мы можем применять их к тому, что мы, разработчики Android, делаем ежедневно — вызывать API.

0. Установка

В Android Studio 3.0 (Preview) теперь есть встроенная поддержка Kotlin, без ручной установки плагинов. Отсюда можно установить preview-версию.

1. Добавление зависимостей

Чтобы использовать Retrofit, вам нужно добавить зависимости в файл build.gradle:

RxJava2 поможет сделать наши вызовы реактивными.
GSON-конвертер будет обрабатывать десериализацию и сериализацию тел запроса и ответа.
RxAndroid поможет нам с привязкой RxJava2 к Android.

2. Создание классов данных

Как правило, следующим шагом является создание классов данных, которые являются POJO (Plain Old Java Objects) и которые будут представлять ответы на вызовы API.

С API Github пользователи будут представлены как объекты.

Как это будет выглядеть на Kotlin:

Классы данных в Котлине

Классы данных в Kotlin — это классы, специально разработанные для хранения данных.

Компилятор Kotlin автоматически помогает нам реализовать методы equals (), hashCode () и toString () в классе, что делает код еще короче, потому что нам не нужно это делать самостоятельно.

Мы можем переопределить реализацию по умолчанию любого из этих методов путем определения метода.

Отличной особенностью является то, что мы можем создавать результаты поиска в одном файле Kotlin — скажем, SearchResponse.kt. Наш окончательный класс ответа на поиск будет содержать все связанные классы данных и выглядеть следующим образом:

SearchResponse.kt

3. Создание API-интерфейса

Следующим шагом, который мы обычно делаем в Java, является создание интерфейса API, который мы будем использовать для создания запросов и получения ответов.

Читайте также:  Как восстановить контакты андроида с аккаунта google

Как правило, в Java я хотел бы создать удобный «фабричный» класс, который создает службу API, когда это необходимо, и я бы сделал что-то вроде этого:

GithubApiService.java

Чтобы использовать этот интерфейс, мы делаем следующие вызовы:

Чтобы повторить тоже самое в Котлине, у нас будет эквивалентный интерфейс GithubApiService.kt, который будет выглядеть так:

GithubApiService.kt

Использование этого интерфейса и фабричного класса будет выглядеть так:

Обратите внимание, что нам не нужно было использовать «имя» сопутствующего объекта для ссылки на метод, мы использовали только имя класса.

Синглтоны и сопутствующие объекты в Котлине

Чтобы понять, какие сопутствующие объекты в Котлине есть, мы должны сначала понять, какие объявления объектов находятся в Котлине. Объявление объекта в Котлине — это способ, которым одиночный элемент создается в Котлине.

Синглтоны в Котлине так же просты, как объявление объекта и присвоение ему имени. Например:

Использование указанного выше объявления объекта:

Благодаря этому мы смогли создать поставщика, который предоставит нам экземпляр репозитория (который поможет нам подключиться к API Github через GithubApiService).

Объявление объекта инициализируется при первом доступе — так же, как работает Singleton.

Однако, объекты-компаньоны — это тип объявления объекта, который соответствует ключевому слову companion. Объекты Companion можно сравнить с статическими методами или полями на Java. Фактически, если вы ссылаетесь на объект-компаньон с Java, он будет выглядеть как статический метод или поле.

Сопутствующий объект — это то, что используется в версии GithubApiService.kt Kotlin выше.

4. Создание репозитория

Поскольку мы стараемся как можно больше абстрагировать наши процессы, мы можем создать простой репозиторий, который обрабатывает вызов GithubApiService и строит строку запроса.

Строка запроса, соответствующая нашей спецификации для этого демонстрационного приложения (для поиска разработчиков Java в Омске) с использованием API Github, — это местоположение: Omsk + language: Java, поэтому мы создадим метод в репозитории, который позволит нам построить эту строку, передавая местоположение и язык в качестве параметров.

Наш поисковый репозиторий будет выглядеть так:

Строковые шаблоны в Котлине

В блоке вышеприведенного кода мы использовали функцию Kotlin, называемую «String templates», чтобы построить нашу строку запроса. Строковые шаблоны начинаются со знака доллара — $ и значение переменной, следующей за ней, конкатенируется с остальной частью строки. Это аналогичная функция для строковой интерполяции в groovy.

5. Делаем запрос и получаем ответ API при помощи RxJava

Теперь, когда мы настроили наши классы ответов, наш интерфейс репозитория, теперь мы можем сделать запрос и получить ответ API с помощью RxJava. Этот шаг похож на то, как мы будем делать это на Java. В коде Kotlin это выглядит так:

Мы сделали наш запрос и получили ответ. Теперь можем делать с ним все, что захотим.

Полезные ссылки:

Заключение

Таким образом, в этом посте мы рассмотрели некоторые интересные возможности/свойства языка Kotlin и способы их применения при использовании Retrofit + RxJava для сетевых вызовов.

  • Классы данных
  • Объявления объектов
  • Сопутствующие объекты
  • Строковые шаблоны
  • Взаимодействие с Java

Источник

OData + RxJava + Retrofit 2 для android приложения

Столкнулся на проекте с проблемой доселе не виданной. Пришлось покурить документацию и в этой статье я расскажу как с помощью RxJava и Retrofit 2 — можно решить задачу по созданию клиента Odata для android приложения.

Спасибо огромное Jake Wharton за создание таких комфортных инструментов.

Добро пожаловать в мир магии

У нас есть приложение, которое по протоколу Odata должно выгребать с сервера данные, отображать их в списках, которые должны подгружаться по мере прокрутки и отправлять данные созданные пользователем на сервер. Тривиальная задача, но не тут то было, то что работает без проблемно на Java — не хочет так же работать с android.

А библиотеки и документация на Odata только от Apache — Olingo и Microsoft на C#.

В данной статье протокол Odata рассматривать я не буду, очень хорошая документация есть у Microsoft и ссылки я оставлю в конце статьи.

Вот вкратце определение с Wiki Open_Data_Protocol

Open Data Protocol (OData) — это открытый веб-протокол для запроса и обновления данных. Протокол позволяет выполнять операции с ресурсами, используя в качестве запросов HTTP-команды, и получать ответы в форматах XML или JSON.

Начиная с версии 4.0, OData — открытый стандарт, одобренный OASIS.

И вот здесь и начинается самое интересное, Odata — это своеобразный SQL в REST API и для динамически создаваемых данных самое то.

Но у нас строго типизированный язык и без знания модели — обработка и хранение данных создают довольно не простую задачу.

Решение которой не может быть типовым и многократно описанным в сети.

Скажу даже больше, кроме этих ссылок на документацию в сети — по теме все плохо.

А теперь займемся магией:

Создаем службу для работы с сетью

Будем использовать Retrofit 2 и сопутствующие продукты компании Square

Все эти зависимости и есть мощнейшая библиотека для работы с с сетью в Java.

Описывать работу с Retrofit 2 не вижу смысла, вот есть хороший мануал: Используем Retrofit 2 в Android-приложении.

Итак, на сервере храниться модель данных Poduct, которая имеет какие то параметры и атрибуты. Все данные идут в формате JSON и для работы нам необходим POJO класс.

Рекомендую в HttpLoggingInterceptor настроить уровень подробности перехвата — Level.BODY.

Делаем запрос listing 4, чтобы максимально вытянуть структуру данных и ответ будет приблизительно в таком формате:

И уже на основании этих данных можно формировать запрос для дальнейших манипуляций с данными.

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

Кульминация и щенячий восторг от комфорта инструмента

И вот он момент истинны, мощь, сила и простота библиотеки Retrofit 2. Теперь можно получить properties используя сервисный документ Odata:

Вот она силушка богатырская библиотеки Retrofit 2. Динамический Url забирает на себя всю эту массу параметров, с которыми можно играться в коде на сколько хватит фантазии.

Итоги

Это был полезный опыт, которым я и спешу поделится, мне в свое время эта статья реально бы убрала кучу проблем и вопросов.

Читайте также:  Modern ops mod menu android

В статье я не стал углубляться в ненужные подробности по Retrofit 2 и OData и указал ссылки на документацию если возникнет необходимость вникнуть глубже.

Полную версию кода предоставить не могу, за что приношу извинения, продукт коммерческий.

Источник

Consuming APIs with Retrofit

Retrofit is a type-safe REST client for Android, Java and Kotlin developed by Square. The library provides a powerful framework for authenticating and interacting with APIs and sending network requests with OkHttp. See this guide to understand how OkHttp works.

This library makes downloading JSON or XML data from a web API fairly straightforward. Once the data is downloaded then it is parsed into a Plain Old Java Object (POJO) which must be defined for each «resource» in the response.

Make sure to require Internet permissions in your AndroidManifest.xml file:

Add the following to your app/build.gradle file:

Note: if you are upgrading from Retrofit 2 beta 1 or beta2, your package imports will need to be changed from import retrofit.XXXX to import retrofit2.XXXX . You will also need to update your OkHttp imports from import okhttp.XXXX to import okhttp3.XXXX because of the new OkHttp3 dependency:

If you intend to use RxJava with Retrofit 2, you will also need to include the RxJava adapter:

adapter-rxjava is now deprecated. Retrofit 2.2 and newer have a first-party call adapter for RxJava 2:(https://github.com/square/retrofit/tree/master/retrofit-adapters/rxjava2)

In the past, Retrofit relied on the Gson library to serialize and deserialize JSON data. Retrofit 2 now supports many different parsers for processing network response data, including Moshi, a library build by Square for efficient JSON parsing. However, there are a few limitations, so if you are not sure which one to choose, use the Gson converter for now.

Converter Library
Gson com.squareup.retrofit2:converter-gson:2.9.0
Jackson com.squareup.retrofit2:converter-jackson:2.9.0
Moshi com.squareup.retrofit2:converter-moshi:2.9.0
Protobuf com.squareup.retrofit2:converter-protobuf:2.9.0
Wire com.squareup.retrofit2:converter-wire:2.9.0
Simple XML com.squareup.retrofit2:converter-simplexml:2.9.0

There are two approaches discussed in this guide. The first way is the manual approach, which requires you to learn how to use the Gson library. The second approach is you can also auto-generate the Java classes you need by capturing the JSON output and using jsonschema2pojo. We encourage you to follow the manual way to best understand how the auto-generated code approach works.

See this guide about leveraging the Gson library for more information about how to create your own Java classes for use with Retrofit. The guide shows how to use Gson to ingest data from the Rotten Tomatoes API, but it can be used in the same way for any RESTful web service.

Assuming you have the JSON response already, go to jsonschema2pojo. Make sure to select JSON as the Source Type:

Set the Annotation style to Gson .

Next, paste the JSON output into the textbox:

Click the Preview button. You should see the top section look sort of like the following:

Paste the generated class into your project under a models sub-package. Rename the class name Example to reflect your model name. For this example, we will call this file and class the User model.

Note: Android does not come normally with many of the javax.annotation library by default. If you wish to keep the @Generated annotation, you will need to add this dependency. See this Stack Overflow discussion for more context. Otherwise, you can delete that annotation and use the rest of the generated code.

To send out network requests to an API, we need to use the Retrofit builder class and specify the base URL for the service.

Note also that we need to specify a factory for deserializing the response using the Gson library. The order in which the converters are added will be the sequence in which they are attempted to be processed as discussed in this video talk. If we wish to pass in a custom Gson parser instance, it can be specified too:

With Retrofit 2, endpoints are defined inside of an interface using special retrofit annotations to encode details about the parameters and request method. In addition, the return value is always a parameterized Call object such as Call . If you do not need any type-specific response, you can specify return value as simply Call .

For instance, the interface defines each endpoint in the following way:

Notice that each endpoint specifies an annotation of the HTTP method (GET, POST, etc.) and method that will be used to dispatch the network call. Note that the parameters of this method can also have special annotations:

Annotation Description
@Path variable substitution for the API endpoint (i.e. username will be swapped for in the URL endpoint).
@Query specifies the query key name with the value of the annotated parameter.
@Body payload for the POST call (serialized from a Java object to a JSON string)
@Header specifies the header with the value of the annotated parameter

Normally, the base URL is defined when you instantiated an Retrofit instance. Retrofit 2 allows you to override the base URL specified by changing it in the annotation (i.e. if you need to keep one specific endpoint using an older API endpoint)

There are also others that allow you to modify the base URL using relative paths (and not the fully qualified URL) as discussed in this blog article.

Notice that there is a @Headers and @Header annotation. The Headers can be used to provide pre-defined ones:

We can also add headers as a parameter to the endpoint:

If we wish to submit form-encoded data, we can use the FormUrlEncoded annotation. The @Field annotation will denote what payload will be submitted as form data.

If we need to upload images or files, we need to send by using Multipart forms. We will to mark the endpoint with @Multipart , and label at least one parameter with @Part.

Assuming we have a reference to the file, we can create a RequestBody object:

If you need to specify a unique filename for your multipart upload, there is currently an issue in Retrofit 2 tracked in this ticket. Alternatively, you can create a multi-part RequestBody according to this OkHttp recipe guide and pass it along as one of the @Part annotated parameters:

If we wish to POST form-encoded name/value pairs, we can use the @FormUrlEncoded and @FieldMap annotations:

Retrofit 2 will use the converter library chosen to handle the deserialization of data from a Java object. If you annotate the parameter with a @Body parameter, this work will be done automatically. If you are using the Gson library for instance, any field belonging to the class will be serialized for you. You can change this name using the @SerializedName decorator:

Our endpoint would look like the following:

We could invoke this API call as follows:

The resulting network call would POST this data:

If you are trying to upgrade from Retrofit 1, you may remember that the last parameter had to be a Callback type if you wanted to define the API call to run asynchronously instead of synchronously:

Retrofit 1 relied on this Callback type as a last parameter to determine whether the API call would be dispatched asynchronously instead of synchronously. To avoid having two different calling patterns, this interface was consolidated in Retrofit 2. You now simply define the return value with a parameterized Call , as shown in the previous section.

We can bring this all together by constructing a service leveraging the MyApiEndpointInterface interface with the defined endpoints:

If we want to consume the API asynchronously, we call the service as follows:

Shown above, Retrofit will download and parse the API data on a background thread, and then deliver the results back to the UI thread via the onResponse or onFailure method.

Note also that OkHttp, which dispatches the callback on the worker thread, callbacks in Retrofit are dispatched on the main thread. Because UI updates can only be done on the main thread, the approach used by Retrofit can make it easier to make changes to your views.

If you are using Retrofit in a Background Service instead of an Activity or Fragment, you can run the network call synchronously within the same thread by using the execute() method.

Retrofit 2 also supports RxJava extensions. You will need to create an RxJava Adapter. By default, all network calls are synchronous:

If you wish to default network calls to be asynchronous, you need to use createWithScheduler() .

You can then instantiate the Retrofit instance:

Instead of creating Call objects, we will use Observable types.

Consistent with the RxJava framework, we need to create a subscriber to handle the response. The methods onCompleted() , onError() , and onNext() need to be added. Using the Android RxJava library, we can also designate that we will handle this event on the UI main thread. Note: If you intend to override the default network call behavior, you can specify subscribeOn() . Otherwise, it can omitted. Note: As the RxJava rewrote their API, the term «Subscription» used here shall be replaced with «Disposable». As the word «Subscription» had conflict intentions.

Note that if you are running any API calls in an activity or fragment, you will need to unsubscribe on the onDestroy() method. The reasons are explained in this Wiki article:

Note also that subscribing an observer to the observable is what triggers the network request. For more information about how to attach multiple observers before dispatching the network requests, see this section.

Headers can be added to a request using an Interceptor . To send requests to an authenticated API, add headers to your requests using an interceptor as outlined below:

Notice that in Retrofit 2 the interceptor has to be added to a custom OkHttpClient . In Retrofit 1, it could be set directly by the builder class.

In order to authenticate with OAuth, we need to sign each network request sent out with a special header that embeds the access token for the user that is obtained during the OAuth process. The actual OAuth process needs to be completed with a third-party library such as signpost and then the access token needs to be added to the header using a request interceptor. Relevant links for Retrofit and authentication below:

Resources for using signpost to authenticate with an OAuth API:

Several other Android OAuth libraries can be explored instead of signpost:

There is a known issue currently with Retrofit 2 passing Lint tests tracked in this ticket. In particular, you may see package reference in library; not included in Android: java.nio.file. Referenced from okio.Okio. or Invalid package reference in library; not included in Android: java.lang.invoke. Referenced from retrofit.Platform.Java8. .

To bypass this issue, create a gradle/lint.xml in your root project:

Add this line to your app/build.gradle file:

The lint errors should be suppressed and not trigger any additional errors for now.

Retrofit and OkHttp can be hard to troubleshoot when trying to step through the various layers of abstraction in the libraries. You can add the HttpLogInterceptor that can be added when using the OkHttp3 library, which will print HTTP requests/responses through LogCat. You can also leverage Facebook’s Stetho project to use Chrome to inspect all network traffic.

To use HttpLogInterceptor , add this dependency to your Gradle configuration:

You will need to add a network interceptor for HttpLogInterceptor. See this doc for the different options that can be used.

You then need to pass this custom OkHttpClient into the Retrofit builder:

Facebook’s Stetho project enables you to use Chrome debugging tools to troubleshoot network traffic, database files, and view layouts. See this guide for more details.

Источник

Читайте также:  Обновления android через kies
Оцените статью