fbpx

Course Content

Total learning: 10 lessons Time: 2 hours

Добавление RxJava 2.0 к проекту и переход от Retrofit Callback к RxJava для получения данных

Мы написали небольшое приложение, которое умеет обращаться к удаленному серверу и выводить полученные данные. Однако подход, использующий callback в Retrofit, является не очень удобным. Например, нам нужно будет сделать несколько запросов на основании ответа предыдущих. В случае со стандартным подходом наш код станет громоздким и трудно поддерживаемым. На помощь приходит библиотека RxJava.

Поэтому в этом разделе мы добавим в проект RxJava 2.0 и научимся делать запросы, используя библиотеку для реактивного программирования RxJava и RxAndroid.  Если вы впервые столкнулись с библиотекой RxJava, то рекомендую пройти созданный мной видеокурс на Stepic  по основам RxJava c примерами.

Код проекта вы можете скачать здесь.

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

Сначало, в проект необходимо добавить следующие зависимости

// RxJava
implementation "io.reactivex.rxjava2:rxjava:2.2.17"
// RxAndroid
implementation "io.reactivex.rxjava2:rxandroid:2.1.1"
// Для использования RxJava c Retrofit
implementation "com.squareup.retrofit2:adapter-rxjava2:2.7.1"

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(RxJava2CallAdapterFactory.create())
            .build()

        return@lazy retrofit.create(MovieApiInterface::class.java)
    }
}

Обратите внимание, мы добавили .addCallAdapterFactory(RxJava2CallAdapterFactory.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. Код проекта вы можете скачать здесь.

Не забудьте присоединиться к нам в Telegram: