Course Content
-
Введение в RxJava 3.0. Способы создания Observable В первом модуле вы узнаете чем отличается Observable от Observer и поймете как создать источник данных
-
Основные операторы RxJava 3.0 Рассмотрим на примерах самые популярные операторы RxJava 3.0 такие как map(), flatMap(), filter() и другие.
-
Выходим в сеть с помощью RxJava
Пример использования RxJava для получения данных из сети
Пришло время внедрить RxJava в реальный проект. Для этого мы будем использовать приложение, которое делает запрос в сеть и отображает список фильмов. Однако подход, использующий callback в Retrofit, является не очень удобным. Например, нам нужно будет сделать несколько запросов на основании ответа предыдущих. В случае со стандартным подходом наш код станет громоздким и трудно поддерживаемым. На помощь приходит библиотека RxJava. Поэтому в этом разделе мы добавим в проект RxJava и научимся делать запросы, используя библиотеку для реактивного программирования RxJava и RxAndroid. Код проекта вы можете скачать здесь.
Для работы с API мы будем использовать TheMovieDatabase API – это бесплатный и удобный источник данных. Чтобы сделать запрос вам понадобится API-токен. Кроме того, для получения данных из сети мы будем использовать Retrofit. В этом туториале рассказывается подробнее как работать с Retrofit и как получить API-токен. А в данном уроке будет сделан фокус на внедрение RxJava.
Добавление зависимостей
Сначало, в проект необходимо добавить следующие зависимости
// RxJava implementation "io.reactivex.rxjava3:rxjava:3.0.0" // RxAndroid implementation "io.reactivex.rxjava3:rxandroid:3.0.0" // Для использования RxJava c Retrofit implementation 'com.squareup.retrofit2:adapter-rxjava3:2.9.0'
RxAndroid – является надстройкой над RxJava, добавляющей несколько классов для использования RxJava на платформе Android. В частности, как вы знаете, в Android запрещено обращаться к серверу из главного потока. Для переключения между фоновым потоком обратно в главный поток, нам понадобится AndroidSchedulers.mainThread() который и находится в RxAndroid. Следующим шагом, после добавления нужных библиотек, необходимо изменить интерфейс, который Retrofit использует для создания запросов к серверу.
Добавление RxJava адаптера к Retrofit
Для использования RxJava необходимо добавить Retrofit адаптер, как показано ниже:
object MovieApiClient { const val BASE_URL = "https://api.themoviedb.org/3/" val apiClient: MovieApiInterface by lazy { val retrofit = Retrofit.Builder() .baseUrl(BASE_URL) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJava3CallAdapterFactory.create()) .build() return@lazy retrofit.create(MovieApiInterface::class.java) } }
Обратите внимание, мы добавили .addCallAdapterFactory(RxJava3CallAdapterFactory.create()) в builder
Замена Retrofit Call на Single
Откройте файл MovieApiInterface.kt и замените вызов
@GET("movie/top_rated") fun getTopRatedMovies(@Query("api_key") apiKey: String, @Query("language") language: String): Call<MoviesResponse>
На следующий код:
@GET("movie/top_rated") fun getTopRatedMovies(@Query("api_key") apiKey: String, @Query("language") language: String): Single<MoviesResponse>
Обратите внимание, что мы заменили Call на Single. Single – похож Observable, но который имеет, только 2 метода: onSuccess(),onError(). То есть, используя Single, вы может, либо получить 1 значение либо получить ошибку. Single рекомендуется использовать для сетевых запросов, где как раз вы можете либо получить ответ от сервера, либо ошибку. Теперь, чтобы получить данные в MainActivity, нам необходимо избавиться от методов Retrofit
Получение данных, используя RxJava и RxAndroid
Для получения данных в стиле Rx, необходимо заменить методы Retrofit на использование RxJava. Для этого замените код в MainActivity.kt
val topRatedMovie = MovieApiClient.apiClient.getTopRatedMovies(API_KEY, "ru") call.enqueue(object : Callback<MoviesResponse> { override fun onResponse( call: Call<MoviesResponse>, response: Response<MoviesResponse> ) { val movies = response.body()!!.results // Передаем результат в adapter и отображаем элементы recyclerView.adapter = MoviesAdapter(movies, R.layout.list_item_movie) } override fun onFailure(call: Call<MoviesResponse>, t: Throwable) { // Логируем ошибку Log.e(TAG, t.toString()) } })
Следующим образом:
// Получаем Single val getTopRatedMovies = MovieApiClient.apiClient.getTopRatedMovies(API_KEY, "ru") getTopRatedMovies .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe( { it -> val movies = it.results // Передаем результат в adapter и отображаем элементы recyclerView.adapter = MoviesAdapter(movies, R.layout.list_item_movie) }, { error -> // Логируем ошибку Log.e(TAG, error.toString()) } )
Давайте кратко пройдёмся по коду. Строчка
// Получаем Single val getTopRatedMovies = MovieApiClient.apiClient.getTopRatedMovies(API_KEY, "ru")
Инициализирует источник данных Single<MoviesResponse> подписавшись на который, мы создадим запрос для получения списка популярных фильмов и получим данные. Далее, с помощью
getTopRatedMovies .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread())
переводим исполнение запроса в поток Schedulers.io() и после того, как он отработает – возвращаемся в UI поток с помощью оператора observeOn, который принимает в качестве аргумента AndroidSchedulers.mainThread(). Далее, так как мы используем Single, то у нас есть 2 варианта обработки: onSuccess и onError в каждом из которых мы соответственно и обрабатываем результаты. Вот и все, таким образом мы убрали использование методов обратного вызова от Retrofit и перешли к использованию RxJava. Код проекта вы можете скачать здесь.
Ну а если вы хотите научиться использовать продвинутые операторы RxJava, научиться объединять запросы и обрабатывать ошибки, то приглашаю вас на следующий поток интенсива по Android-разработке на Kotlin. Мы рассмотрим продвинутые операторы: zip, merge, concat, combineLatest, concatMap и другие, научимся использовать Subject и обуздаем Backpressure. Подробнее 👈
Не забудьте присоединиться к нам в Telegram в канале AndroidSchool.ru
- в канале AndroidSchool.ru публикуются полезные материалы для Android-разработчика и анонсы новых курсов
- новый чат @android_school_talk задаём вопросы и предлагаем идеи для улучшения курсов на AndroidSchool.ru
- Практический онлайн-интенсив по Android-разработке с ментором и code review