fbpx

Course Content

Total learning: 16 lessons Time: 1 week

Пример использования 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