Top Related Projects
RxJava – Reactive Extensions for the JVM – a library for composing asynchronous and event-based programs using observable sequences for the Java VM.
Reactive Programming in Swift
Library support for Kotlin coroutines
RxJava binding APIs for Android's UI widgets.
Mavericks: Android on Autopilot
Quick Overview
RxKotlin is a Kotlin implementation of ReactiveX, a library for composing asynchronous and event-based programs using observable sequences. It extends the ReactiveX family to Kotlin, providing a powerful set of tools for handling asynchronous data streams and event-based programming in a functional, reactive style.
Pros
- Seamless integration with Kotlin's language features and syntax
- Powerful operators for transforming, combining, and manipulating observable streams
- Excellent for managing complex asynchronous operations and event-driven programming
- Strong interoperability with Java and Android development
Cons
- Steep learning curve for developers new to reactive programming
- Can lead to overly complex code if not used judiciously
- Potential performance overhead for simple use cases
- Limited documentation compared to RxJava
Code Examples
- Creating and subscribing to an Observable:
import io.reactivex.rxkotlin.toObservable
val numbers = listOf(1, 2, 3, 4, 5)
numbers.toObservable()
.subscribe { println(it) }
- Using operators to transform data:
import io.reactivex.rxkotlin.toObservable
val numbers = listOf(1, 2, 3, 4, 5)
numbers.toObservable()
.map { it * 2 }
.filter { it > 5 }
.subscribe { println(it) }
- Combining multiple Observables:
import io.reactivex.Observable
val obs1 = Observable.just(1, 2, 3)
val obs2 = Observable.just(4, 5, 6)
Observable.zip(obs1, obs2) { a, b -> a + b }
.subscribe { println(it) }
Getting Started
To start using RxKotlin in your project, add the following dependency to your build.gradle
file:
dependencies {
implementation 'io.reactivex.rxjava2:rxkotlin:2.4.0'
}
For Maven users, add this to your pom.xml
:
<dependency>
<groupId>io.reactivex.rxjava2</groupId>
<artifactId>rxkotlin</artifactId>
<version>2.4.0</version>
</dependency>
After adding the dependency, you can start using RxKotlin in your Kotlin code by importing the necessary classes and functions from the io.reactivex
package.
Competitor Comparisons
RxJava – Reactive Extensions for the JVM – a library for composing asynchronous and event-based programs using observable sequences for the Java VM.
Pros of RxJava
- More mature and widely adopted in the Java ecosystem
- Extensive documentation and community support
- Broader range of operators and utilities
Cons of RxJava
- Verbose syntax compared to Kotlin-specific implementations
- Lacks some Kotlin-specific language features and idioms
- May require additional setup for Kotlin projects
Code Comparison
RxJava:
Observable.just("Hello", "World")
.map(String::toUpperCase)
.subscribe(System.out::println);
RxKotlin:
Observable.just("Hello", "World")
.map { it.toUpperCase() }
.subscribe { println(it) }
RxKotlin provides a more concise syntax leveraging Kotlin's language features, such as lambda expressions and type inference. While both libraries offer similar functionality, RxKotlin is tailored specifically for Kotlin projects, providing a more idiomatic and streamlined experience for Kotlin developers.
RxJava remains a solid choice for Java projects and mixed Java/Kotlin codebases, offering a wealth of resources and a large community. However, for pure Kotlin projects, RxKotlin may provide a more natural fit, integrating seamlessly with Kotlin's language features and conventions.
Reactive Programming in Swift
Pros of RxSwift
- More mature and stable ecosystem for iOS development
- Extensive documentation and community support
- Better integration with Swift's type system and language features
Cons of RxSwift
- Steeper learning curve for developers new to reactive programming
- Potential performance overhead in complex scenarios
- Limited compatibility with older iOS versions
Code Comparison
RxSwift:
Observable.from([1, 2, 3, 4, 5])
.filter { $0 % 2 == 0 }
.map { $0 * 2 }
.subscribe(onNext: { print($0) })
RxKotlin:
Observable.fromIterable(listOf(1, 2, 3, 4, 5))
.filter { it % 2 == 0 }
.map { it * 2 }
.subscribe { println(it) }
Both RxSwift and RxKotlin provide similar functionality for reactive programming in their respective languages. The syntax is quite similar, with minor differences in method names and language-specific features. RxSwift benefits from Swift's strong type system and iOS-specific optimizations, while RxKotlin leverages Kotlin's concise syntax and multiplatform capabilities. Developers familiar with one can easily transition to the other, as the core concepts remain consistent across ReactiveX implementations.
Library support for Kotlin coroutines
Pros of kotlinx.coroutines
- Lightweight and more idiomatic Kotlin syntax
- Built-in support for structured concurrency
- Better integration with Kotlin's suspend functions
Cons of kotlinx.coroutines
- Steeper learning curve for developers new to coroutines
- Less extensive ecosystem compared to RxKotlin
- Limited support for backpressure handling
Code Comparison
kotlinx.coroutines:
suspend fun fetchData() = coroutineScope {
val result1 = async { api.fetchItem1() }
val result2 = async { api.fetchItem2() }
result1.await() + result2.await()
}
RxKotlin:
fun fetchData(): Single<Result> {
return Single.zip(
api.fetchItem1().subscribeOn(Schedulers.io()),
api.fetchItem2().subscribeOn(Schedulers.io()),
{ r1, r2 -> r1 + r2 }
)
}
Both libraries offer powerful concurrency tools for Kotlin developers. kotlinx.coroutines provides a more native Kotlin experience with structured concurrency, while RxKotlin offers a rich set of operators and better backpressure handling. The choice between them often depends on project requirements and team familiarity with reactive programming concepts.
RxJava binding APIs for Android's UI widgets.
Pros of RxBinding
- Specifically designed for Android UI components, offering seamless integration with Android views
- Provides pre-built bindings for common Android UI elements, reducing boilerplate code
- Offers more granular control over UI-specific events and interactions
Cons of RxBinding
- Limited to Android platform, whereas RxKotlin is more versatile and can be used in various Kotlin projects
- Smaller community and fewer resources compared to the more general-purpose RxKotlin
- May require additional learning curve for developers not familiar with Android-specific reactive programming
Code Comparison
RxBinding (Android-specific):
RxView.clicks(button)
.subscribe { /* Handle button click */ }
RxKotlin (General-purpose):
Observable.fromCallable { /* Perform operation */ }
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe { /* Handle result */ }
RxBinding focuses on UI-specific reactive programming, while RxKotlin provides a more general-purpose reactive programming solution for Kotlin projects. RxBinding is ideal for Android developers looking to simplify UI interactions, while RxKotlin offers broader applicability across different types of Kotlin applications.
Mavericks: Android on Autopilot
Pros of Mavericks
- Specifically designed for Android development, offering a more tailored solution
- Provides a robust architecture pattern (MvRx) for building complex UIs
- Integrates well with Jetpack Compose for modern Android UI development
Cons of Mavericks
- Steeper learning curve for developers not familiar with the MvRx pattern
- Less flexibility compared to RxKotlin's general-purpose reactive programming
- Limited to Android development, whereas RxKotlin can be used in various Kotlin projects
Code Comparison
Mavericks (MvRx) example:
class MyViewModel(initialState: MyState) : MavericksViewModel<MyState>(initialState) {
fun updateData() = setState { copy(data = "New Data") }
}
RxKotlin example:
val observable = Observable.just("Data")
.map { it.uppercase() }
.subscribe { println(it) }
Mavericks focuses on state management and UI updates, while RxKotlin provides general reactive programming constructs. Mavericks is more opinionated about architecture, whereas RxKotlin offers more flexibility but requires more setup for similar functionality in Android development.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
RxKotlin
Kotlin Extensions for RxJava
RxKotlin is a lightweight library that adds convenient extension functions to RxJava. You can use RxJava with Kotlin out-of-the-box, but Kotlin has language features (such as extension functions) that can streamline usage of RxJava even more. RxKotlin aims to conservatively collect these conveniences in one centralized library, and standardize conventions for using RxJava with Kotlin.
import io.reactivex.rxjava3.kotlin.subscribeBy
import io.reactivex.rxjava3.kotlin.toObservable
fun main() {
val list = listOf("Alpha", "Beta", "Gamma", "Delta", "Epsilon")
list.toObservable() // extension function for Iterables
.filter { it.length >= 5 }
.subscribeBy( // named arguments for lambda Subscribers
onNext = { println(it) },
onError = { it.printStackTrace() },
onComplete = { println("Done!") }
)
}
Contributing
:warning: (16/10/2023) We are currently not accepting contributions due to lack of developers capable of handling them in a reasonable manner.
Since Kotlin makes it easy to implement extensions for anything and everything, this project has to be conservative in what features are in scope. Intentions to create syntactic sugar can quickly regress into syntactic saccharin, and such personal preferences belong in one's internal domain rather than an OSS library.
Here are some basic guidelines to determine whether your contribution might be in scope for RxKotlin:
- Is this intended feature already in RxJava?
- If no, propose the operator in RxJava.
- If yes, can Kotlin streamline the operator further?
- Does this substantially reduce the amount of boilerplate code?
- Does this make an existing operator easier to use?
- Does RxJava not contain this feature due to Java language limitations, or because of a deliberate decision to not include it?
Kotlin Slack Channel
Join us on the #rx channel in Kotlin Slack!
https://kotlinlang.slack.com/messages/rx
Support for RxJava 3.x, RxJava 2.x and RxJava 1.x
Use RxKotlin 3.x versions to target RxJava 3.x.
- The 3.x version is active.
Use RxKotlin 2.x versions to target RxJava 2.x.
- The 2.x version of RxJava and RxKotlin is in maintenance mode and will be supported only through bugfixes. No new features or behavior changes will be accepted or applied.
Use RxKotlin 1.x versions to target RxJava 1.x.
- The 1.x version of RxJava and RxKotlin reached end-of-life. No further development, support, maintenance, PRs or updates will happen.
The maintainers do not update the RxJava dependency version for every minor or patch RxJava release, so you should explicitly add the desired RxJava dependency version to your pom.xml
or build.gradle(.kts)
.
Binaries
Binaries and dependency information for Maven, Ivy, Gradle and others can be found at http://search.maven.org.
RxKotlin 3.x
Example for Maven:
<dependency>
<groupId>io.reactivex.rxjava3</groupId>
<artifactId>rxkotlin</artifactId>
<version>3.x.y</version>
</dependency>
Example for Gradle:
implementation("io.reactivex.rxjava3:rxkotlin:3.x.y")
RxKotlin 2.x
Example for Maven:
<dependency>
<groupId>io.reactivex.rxjava2</groupId>
<artifactId>rxkotlin</artifactId>
<version>2.x.y</version>
</dependency>
Example for Gradle:
implementation("io.reactivex.rxjava2:rxkotlin:2.x.y")
RxKotlin 1.x
Example for Maven:
<dependency>
<groupId>io.reactivex</groupId>
<artifactId>rxkotlin</artifactId>
<version>1.x.y</version>
</dependency>
Example for Gradle:
implementation("io.reactivex:rxkotlin:1.x.y")
Building with JitPack
You can also use Gradle or Maven with JitPack to build directly off a snapshot, branch, or commit of this repository.
For example, to build off the 3.x branch, use this setup for Gradle:
repositories {
maven { url 'https://jitpack.io' }
}
dependencies {
implementation 'com.github.ReactiveX:RxKotlin:3.x-SNAPSHOT'
}
Use this setup for Maven:
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
<dependency>
<groupId>com.github.ReactiveX</groupId>
<artifactId>RxKotlin</artifactId>
<version>3.x-SNAPSHOT</version>
</dependency>
Learn more about building this project with JitPack here.
Extensions
Target Type | Method | Return Type | Description |
---|---|---|---|
BooleanArray | toObservable() | Observable | Turns a Boolean array into an Observable |
ByteArray | toObservable() | Observable | Turns a Byte array into an Observable |
ShortArray | toObservable() | Observable | Turns a Short array into an Observable |
IntArray | toObservable() | Observable | Turns an Int array into an Observable |
LongArray | toObservable() | Observable | Turns a Long array into an Observable |
FloatArray | toObservable() | Observable | Turns a Float array into an Observable |
DoubleArray | toObservable() | Observable | Turns a Double array into an Observable |
Array | toObservable() | Observable | Turns a T array into an Observable |
IntProgression | toObservable() | Observable | Turns an IntProgression into an Observable |
Iterable | toObservable() | Observable | Turns an Iterable<T> into an Observable |
Iterator | toObservable() | Observable | Turns an Iterator<T> into an Observable |
Observable | flatMapSequence() | Observable | Flat maps each T emission to a Sequence<R> |
Observable<Pair<A,B>> | toMap() | Single<Map<A,B>> | Collects Pair<A,B> emissions into a Map<A,B> |
Observable<Pair<A,B>> | toMultimap() | Single<Map<A, List<B>> | Collects Pair<A,B> emissions into a Map<A,List<B>> |
Observable<Observable | mergeAll() | Observable | Merges all Observables emitted from an Observable |
Observable<Observable | concatAll() | Observable | Concatenates all Observables emitted from an Observable |
Observable<Observable | switchLatest() | Observable | Emits from the last emitted Observable |
Observable<*> | cast() | Observable | Casts all emissions to the reified type |
Observable<*> | ofType() | Observable | Filters all emissions to only the reified type |
Iterable<Observable | merge() | Observable | Merges an Iterable of Observables into a single Observable |
Iterable<Observable | mergeDelayError() | Observable | Merges an Iterable of Observables into a single Observable, but delays any error |
BooleanArray | toFlowable() | Flowable | Turns a Boolean array into an Flowable |
ByteArray | toFlowable() | Flowable | Turns a Byte array into an Flowable |
ShortArray | toFlowable() | Flowable | Turns a Short array into an Flowable |
IntArray | toFlowable() | Flowable | Turns an Int array into an Flowable |
LongArray | toFlowable() | Flowable | Turns a Long array into an Flowable |
FloatArray | toFlowable() | Flowable | Turns a Float array into an Flowable |
DoubleArray | toFlowable() | Flowable | Turns a Double array into an Flowable |
Array | toFlowable() | Flowable | Turns a T array into an Flowable |
IntProgression | toFlowable() | Flowable | Turns an IntProgression into an Flowable |
Iterable | toFlowable() | Flowable | Turns an Iterable<T> into an Flowable |
Iterator | toFlowable() | Flowable | Turns an Iterator<T> into an Flowable |
Flowable | flatMapSequence() | Flowable | Flat maps each T emission to a Sequence<R> |
Flowable<Pair<A,B>> | toMap() | Single<Map<A,B>> | Collects Pair<A,B> emissions into a Map<A,B> |
Flowable<Pair<A,B>> | toMultimap() | Single<Map<A, List<B>>> | Collects Pair<A,B> emissions into a Map<A,List<B>> |
Flowable<Flowable | mergeAll() | Flowable | Merges all Flowables emitted from an Flowable |
Flowable<Flowable | concatAll() | Flowable | Concatenates all Flowables emitted from an Flowable |
Flowable<Flowable | switchLatest() | Flowable | Emits from the last emitted Flowable |
Flowable | cast() | Flowable | Casts all emissions to the reified type |
Flowable | ofType() | Flowable | Filters all emissions to only the reified type |
Iterable<Flowable | merge() | Flowable | Merges an Iterable of Flowables into a single Flowable |
Iterable<Flowable | mergeDelayError() | Flowable | Merges an Iterable of Flowables into a single Flowable, but delays any error |
Single | cast() | Single | Casts all emissions to the reified type |
Observable<Single | mergeAllSingles() | Observable | Merges all Singles emitted from an Observable |
Flowable<Single | mergeAllSingles() | Flowable | Merges all Singles emitted from a Flowable |
Maybe | cast() | Maybe | Casts any emissions to the reified type |
Maybe | ofType() | Maybe | Filters any emission that is the reified type |
Observable<Maybe | mergeAllMaybes() | Observable | Merges all emitted Maybes |
Flowable<Maybe | mergeAllMaybes() | Flowable | Merges all emitted Maybes |
Action | toCompletable() | Completable | Turns an Action into a Completable |
Callable | toCompletable() | Completable | Turns a Callable into a Completable |
Future | toCompletable() | Completable | Turns a Future into a Completable |
(() -> Any) | toCompletable() | Completable | Turns a (() -> Any) into a Completable |
Observable | mergeAllCompletables() | Completable> | Merges all emitted Completables |
Flowable | mergeAllCompletables() | Completable | Merges all emitted Completables |
Observable | subscribeBy() | Disposable | Allows named arguments to construct an Observer |
Flowable | subscribeBy() | Disposable | Allows named arguments to construct a Subscriber |
Single | subscribeBy() | Disposable | Allows named arguments to construct a SingleObserver |
Maybe | subscribeBy() | Disposable | Allows named arguments to construct a MaybeObserver |
Completable | subscribeBy() | Disposable | Allows named arguments to construct a CompletableObserver |
Observable | blockingSubscribeBy() | Unit | Allows named arguments to construct a blocking Observer |
Flowable | blockingSubscribeBy() | Unit | Allows named arguments to construct a blocking Subscriber |
Single | blockingSubscribeBy() | Unit | Allows named arguments to construct a blocking SingleObserver |
Maybe | blockingSubscribeBy() | Unit | Allows named arguments to construct a blocking MaybeObserver |
Completable | blockingSubscribeBy() | Unit | Allows named arguments to construct a blocking CompletableObserver |
Disposable | addTo() | Disposable | Adds a Disposable to the specified CompositeDisposable |
CompositeDisposable | plusAssign() | Disposable | Operator function to add a Disposable to thisCompositeDisposable |
SAM Helpers (made obsolete since Kotlin 1.4)
These methods have been made obsolete with new type inference algorithm in Kotlin 1.4. They will be removed in some future RxKotlin version.
To help cope with the SAM ambiguity issue when using RxJava with Kotlin, there are a number of helper factories and extension functions to workaround the affected operators.
Observables.zip()
Observables.combineLatest()
Observable#zipWith()
Observable#withLatestFrom()
Flowables.zip()
Flowables.combineLatest()
Flowable#zipWith()
Flowable#withLatestFrom()
Singles.zip()
Single#zipWith()
Maybes.zip()
Usage with Other Rx Libraries
RxKotlin can be used in conjunction with other Rx and Kotlin libraries, such as RxAndroid, RxBinding, and TornadoFX/RxKotlinFX. These libraries and RxKotlin are modular, and RxKotlin is merely a set of extension functions to RxJava that can be used with these other libraries. There should be no overlap or dependency issues.
Other Resources
Learning RxJava Packt Book
Chapter 12 of Learning RxJava covers RxKotlin and Kotlin idioms with RxJava.
Reactive Programming in Kotlin Packt Book
The book Reactive Programming in Kotlin mainly focuses on RxKotlin, as well as learning reactive programming with Kotlin.
Top Related Projects
RxJava – Reactive Extensions for the JVM – a library for composing asynchronous and event-based programs using observable sequences for the Java VM.
Reactive Programming in Swift
Library support for Kotlin coroutines
RxJava binding APIs for Android's UI widgets.
Mavericks: Android on Autopilot
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot