← Назад к вопросам

В чем разница между Single и Observable в RxJava?

2.0 Middle🔥 121 комментариев
#Многопоточность и асинхронность#Работа с данными

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Разница между Single и Observable в RxJava

Single и Observable — это два разных типа источников данных в RxJava, каждый с собственной семантикой и областью применения. Понимание различий критично для правильного использования реактивного программирования в Android.

Observable — ноль, один или много значений

Observable может выделить:

  • Ноль значений (только onComplete)
  • Одно значение
  • Много значений
  • Ошибку
// Observable может выделить несколько значений
fun getNumbers(): Observable<Int> {
    return Observable.create { emitter ->
        emitter.onNext(1)
        emitter.onNext(2)
        emitter.onNext(3)
        emitter.onComplete()
    }
}

getNumbers().subscribe(
    { value -> println("Value: $value") },     // onNext
    { error -> println("Error: $error") },     // onError
    { println("Complete") }                    // onComplete
)
// Вывод:
// Value: 1
// Value: 2
// Value: 3
// Complete

Контракт Observable:

interface Observer<T> {
    fun onNext(value: T)      // может быть вызвано много раз
    fun onError(error: Throwable)
    fun onComplete()           // опционально
}

Single — ровно одно значение или ошибка

Single гарантирует, что:

  • Выделит ровно ОДНО значение
  • Или выделит ошибку
  • Никогда не выделит onComplete без значения
// Single выделяет ровно одно значение
fun getUser(userId: String): Single<User> {
    return Single.create { emitter ->
        val user = User(userId, "John")
        emitter.onSuccess(user) // ровно один результат
    }
}

getUser("1").subscribe(
    { user -> println("User: ${user.name}") },  // onSuccess
    { error -> println("Error: $error") }       // onError
)
// Вывод:
// User: John

Контракт Single:

interface SingleObserver<T> {
    fun onSuccess(value: T)    // ровно один раз
    fun onError(error: Throwable)
    // Нет onComplete!
}

Сравнительная таблица

АспектObservableSingle
Количество значений0, 1 или многоРовно 1
Callback onNextДа (много раз)Нет
Callback onSuccessНетДа (один раз)
Callback onCompleteДа (опционально)Нет
Callback onErrorДаДа
ИспользованиеПотоки, событияЕдиничные запросы

Практические примеры

Observable — для потоков данных:

// Клики на кнопку (может быть много)
fun onButtonClicks(): Observable<Unit> {
    return RxView.clicks(button).map { Unit }
}

onButtonClicks().subscribe { 
    println("Button clicked!")
}

Observable — для sensor данных:

fun getSensorUpdates(): Observable<SensorEvent> {
    return Observable.create { emitter ->
        sensorManager.registerListener(
            object : SensorEventListener {
                override fun onSensorChanged(event: SensorEvent) {
                    emitter.onNext(event)
                }
                override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {}
            },
            sensor,
            SensorManager.SENSOR_DELAY_NORMAL
        )
    }
}

Single — для HTTP запроса:

// Запрос к API — возвращает одно значение
fun getUserFromAPI(userId: String): Single<User> {
    return apiService.getUser(userId)
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
}

getUserFromAPI("1").subscribe(
    { user -> updateUI(user) },
    { error -> showError(error) }
)

Single — для database запроса:

fun getUserFromDatabase(userId: String): Single<User> {
    return Single.fromCallable {
        database.userDao().getUser(userId)
    }.subscribeOn(Schedulers.io())
}

Другие типы в RxJava

Maybe — 0 или 1 значение:

fun getOptionalUser(): Maybe<User> {
    return Maybe.create { emitter ->
        val user = userRepository.findUser()
        if (user != null) {
            emitter.onSuccess(user)
        } else {
            emitter.onComplete() // no value
        }
    }
}

getOptionalUser().subscribe(
    { user -> println("User: $user") },
    { error -> println("Error: $error") },
    { println("No user found") }
)

Completable — нет значения, только успех/ошибка:

fun deleteUser(userId: String): Completable {
    return Completable.fromCallable {
        database.userDao().delete(userId)
    }
}

deleteUser("1").subscribe(
    { println("Deleted") },
    { error -> println("Error: $error") }
)

Преобразование между типами

Observable → Single (берём первый элемент):

getNumbers() // Observable<Int>
    .firstOrError() // Single<Int>
    .subscribe({ value -> println(value) })

Single → Observable:

getUser() // Single<User>
    .toObservable() // Observable<User>
    .subscribe({ user -> println(user) })

Observable → Completable (игнорируем значения):

getNumbers() // Observable<Int>
    .ignoreElements() // Completable
    .subscribe({ println("Done") })

Практический совет

// Используй Single для:
// - HTTP запросов (GET, POST)
// - Database запросов
// - Операций, которые должны вернуть ровно один результат

// Используй Observable для:
// - Потоков событий (клики, touch events)
// - Sensor данных
// - Real-time обновлений
// - Потоков, которые могут быть пусты или иметь много значений

Миграция на Kotlin Coroutines

В современной Android разработке рекомендуется использовать Kotlin Coroutines вместо RxJava:

// RxJava Single
fun getUser(): Single<User> { ... }

// Kotlin Coroutines (современный подход)
suspend fun getUser(): User { ... }

Однако RxJava по-прежнему широко используется в legacy проектах и имеет мощный экосистем операторов для сложной обработки потоков.

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

В чем разница между Single и Observable в RxJava? | PrepBro