Реактивное программирование в Kotlin: библиотека RxKotlin и корутины

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Реактивное программирование в Kotlin: от RxKotlin до корутин

Реактивное программирование — это парадигма, ориентированная на асинхронную обработку потоков данных и распространение изменений. В экосистеме Kotlin эта концепция реализована двумя основными способами: через библиотеку RxKotlin (реактивные расширения для Kotlin на базе RxJava) и через встроенный механизм корутин с Flow. В этой статье мы подробно разберём оба подхода, их особенности и примеры использования.

Что такое реактивное программирование?

Основная идея реактивного программирования — работать с данными как с непрерывными потоками (streams). Вместо того чтобы запрашивать данные и ждать ответа, вы подписываетесь на поток и реагируете на каждое новое событие. Это особенно полезно для UI-приложений, обработки пользовательского ввода, сетевых запросов и работы с базами данных.

Библиотека RxKotlin

RxKotlin — это обёртка над RxJava, которая добавляет удобные расширения для Kotlin, такие как лямбды, функции-расширения и поддержку null-безопасности. Основные типы:

  • Observable<T> — поток, который может испускать от 0 до N элементов и завершаться ошибкой или успешно.
  • Single<T> — поток, испускающий ровно один элемент или ошибку.
  • Flowable<T> — поток с поддержкой backpressure (управление скоростью потребления).
  • Completable — поток, который только завершается (успех/ошибка) без данных.

Пример RxKotlin

import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.schedulers.Schedulers

fun main() {
    val observable = Observable.create<String> { emitter ->
        emitter.onNext("Привет")
        emitter.onNext("из")
        emitter.onNext("RxKotlin")
        emitter.onComplete()
    }

    observable
        .subscribeOn(Schedulers.io())
        .observeOn(Schedulers.single())
        .subscribe(
            { value -> println("Получено: $value") },
            { error -> println("Ошибка: ${error.message}") },
            { println("Поток завершён") }
        )

    Thread.sleep(1000) // Ждём завершения асинхронных операций
}

В этом примере создаётся Observable, который испускает три строки и завершается. Операторы subscribeOn и observeOn управляют потоками выполнения.

Корутины и Flow в Kotlin

Начиная с Kotlin 1.3, корутины стали частью языка, а Flow (введён в 1.3.70) — это реактивный поток, полностью интегрированный с корутинами. Преимущества перед RxKotlin:

  • Меньше накладных расходов (легковесные корутины vs потоки Java).
  • Естественная интеграция с suspend-функциями.
  • Поддержка structured concurrency (автоматическая отмена при завершении scope).
  • Более чистый синтаксис без callback-ов.

Пример Flow

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*

fun main() = runBlocking {
    val flow = flow {
        for (i in 1..5) {
            delay(100) // Имитация асинхронной работы
            emit(i)    // Испускаем элемент
        }
    }

    flow
        .map { it * it } // Преобразование
        .catch { e -> println("Ошибка: $e") }
        .collect { value -> println("Квадрат: $value") }
}

Flow ленив: данные начинают генерироваться только при вызове collect. Операторы map, filter, flatMapConcat работают так же, как в Rx.

Сравнение RxKotlin и Flow

Характеристика RxKotlin Flow + корутины
Зависимости io.reactivex.rxjava3:rxkotlin Встроен в kotlinx.coroutines
Backpressure Flowable, Observable (разные стратегии) Встроенный (через buffer, conflate)
Отмена Disposable (ручная отписка)

Рекомендаций