{"id":18152278,"url":"https://github.com/badoo/reaktive","last_synced_at":"2025-05-14T07:08:14.736Z","repository":{"id":37251640,"uuid":"174194386","full_name":"badoo/Reaktive","owner":"badoo","description":"Kotlin multi-platform implementation of Reactive Extensions","archived":false,"fork":false,"pushed_at":"2025-05-12T10:32:13.000Z","size":16952,"stargazers_count":1188,"open_issues_count":3,"forks_count":60,"subscribers_count":25,"default_branch":"master","last_synced_at":"2025-05-12T11:32:40.745Z","etag":null,"topics":["android","cross-platform","hacktoberfest","ios","kotlin","kotlin-multiplatform","kotlin-native","multi-platform","multiplatform","reactive","reaktive","rx","rxkotlin"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/badoo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2019-03-06T18:00:02.000Z","updated_at":"2025-05-06T05:06:48.000Z","dependencies_parsed_at":"2024-06-03T20:32:54.401Z","dependency_job_id":"bb9f73e2-c43f-413c-bf7e-3a12a9d7948e","html_url":"https://github.com/badoo/Reaktive","commit_stats":null,"previous_names":[],"tags_count":44,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/badoo%2FReaktive","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/badoo%2FReaktive/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/badoo%2FReaktive/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/badoo%2FReaktive/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/badoo","download_url":"https://codeload.github.com/badoo/Reaktive/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254092776,"owners_count":22013290,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","cross-platform","hacktoberfest","ios","kotlin","kotlin-multiplatform","kotlin-native","multi-platform","multiplatform","reactive","reaktive","rx","rxkotlin"],"created_at":"2024-11-02T02:06:21.778Z","updated_at":"2025-05-14T07:08:14.709Z","avatar_url":"https://github.com/badoo.png","language":"Kotlin","readme":"# \u003cimg src=\"https://raw.githubusercontent.com/badoo/Reaktive/master/assets/logo_reaktive.png\" height=\"36\"\u003e\n\n[![Maven Central](https://img.shields.io/maven-central/v/com.badoo.reaktive/reaktive?color=blue)](https://search.maven.org/artifact/com.badoo.reaktive/reaktive)\n[![Build Status](https://github.com/badoo/Reaktive/workflows/Build/badge.svg?branch=master)](https://github.com/badoo/Reaktive/actions)\n[![License](https://img.shields.io/badge/License-Apache/2.0-blue.svg)](https://github.com/badoo/Reaktive/blob/master/LICENSE)\n[![kotlinlang|reaktive](https://img.shields.io/badge/kotlinlang-reaktive-blue?logo=slack)](https://kotlinlang.slack.com/archives/CU05HB31A)\n\nKotlin multiplatform implementation of Reactive Extensions.\n\nShould you have any questions or feedback welcome to the **Kotlin Slack channel**: \n[#reaktive](https://kotlinlang.slack.com/archives/CU05HB31A)\n\n## Setup\n\nThere are a number of modules published to Maven Central:\n\n- `reaktive` - the main Reaktive library (multiplatform)\n- `reaktive-annotations` - collection of annotations (mutiplatform)\n- `reaktive-testing` - testing utilities (multiplatform)\n- `utils` - some utilities like `Clock`, `AtomicReference`, `Lock`, etc. (multiplatform)\n- `coroutines-interop` - Kotlin coroutines interoperability helpers (multiplatform)\n- `rxjava2-interop` - RxJava v2 interoperability helpers (JVM and Android)\n- `rxjava3-interop` - RxJava v3 interoperability helpers (JVM and Android)\n\n### Configuring dependencies\n\n```groovy\nkotlin {\n    sourceSets {\n        commonMain {\n            dependencies {\n                implementation 'com.badoo.reaktive:reaktive:\u003cversion\u003e'\n                implementation 'com.badoo.reaktive:reaktive-annotations:\u003cversion\u003e'\n                implementation 'com.badoo.reaktive:coroutines-interop:\u003cversion\u003e' // For interop with coroutines\n                implementation 'com.badoo.reaktive:rxjava2-interop:\u003cversion\u003e' // For interop with RxJava v2\n                implementation 'com.badoo.reaktive:rxjava3-interop:\u003cversion\u003e' // For interop with RxJava v3\n            }\n        }\n\n        commonTest {\n            dependencies {\n                implementation 'com.badoo.reaktive:reaktive-testing:\u003cversion\u003e'\n            }\n        }\n    }\n}\n```\n\n## Features:\n\n* Multiplatform: JVM, Android, iOS, macOS, watchOS, tvOS, JavaScript, Linux X64\n* Schedulers support: \n  * `computationScheduler` - fixed thread pool equal to a number of cores\n  * `ioScheduler` - unbound thread pool with caching policy\n  * `newThreadScheduler` - creates a new thread for each unit of work\n  * `singleScheduler` - executes tasks on a single shared background thread\n  * `trampolineScheduler` - queues tasks and executes them on one of the participating threads\n  * `mainScheduler` - executes tasks on main thread\n* True multithreading for Kotlin/Native (since v2.0 only the [new memory model](https://kotlinlang.org/docs/native-memory-manager.html) is supported)\n* Supported sources: `Observable`, `Maybe`, `Single`, `Completable`\n* Subjects: `PublishSubject`, `BehaviorSubject`, `ReplaySubject`, `UnicastSubject`\n* Interoperability with Kotlin Coroutines\n  * Convert `suspend` functions to/from `Single`, `Maybe` and `Completable`\n  * Convert `Flow` to/from `Observable`\n  * Convert `CoroutineContext` to `Scheduler`\n  * Convert `Scheduler` to `CoroutineDispatcher`\n* Interoperability with RxJava2 and RxJava3\n  * Conversion of sources and schedulers between Reaktive and RxJava\n\n## Reaktive and Kotlin/Native \n\nSince version 2.x, Reaktive only works with the [new memory model](https://kotlinlang.org/docs/native-memory-manager.html).\n\n\u003cdetails\u003e\n    \u003csummary\u003e\u003cb\u003eReaktive 1.x and the old (strict) memory model\u003c/b\u003e\u003c/summary\u003e\n\nThe old (strict) Kotlin Native memory model and concurrency are very special. In general shared mutable state between threads is not allowed.\nSince Reaktive supports multithreading in Kotlin Native, please read the following documents before using it:\n\n* [Concurrency](https://kotlinlang.org/docs/reference/native/concurrency.html#object-transfer-and-freezing)\n* [Immutability](https://kotlinlang.org/docs/reference/native/immutability.html)\n\nObject detachment is relatively difficult to achieve and is very error-prone when the objects are created from outside and\nare not fully managed by the library. This is why Reaktive prefers frozen state. Here are some hints:\n\n* Any callback (and any captured objects) submitted to a Scheduler will be frozen\n* `subscribeOn` freezes both its upstream source and downstream observer,\nall the Disposables (upstream's and downstream's) are frozen as well,\nall the values (including errors) are **not** frozen by the operator\n* `observeOn` freezes only its downstream observer and all the values (including errors) passed through it, plus all the Disposables,\nupstream source is **not** frozen by the operator\n* Other operators that use scheduler (like `debounce`, `timer`, `delay`, etc.) behave same as `observeOn` in most of the cases\n\n#### Thread local tricks to avoid freezing\n\nSometimes freezing is not acceptable, e.g. we might want to load some data in background and then update the UI.\nObviously UI can not be frozen. With Reaktive it is possible to achieve such a behaviour in two ways:\n\nUse `threadLocal` operator:\n\n```kotlin\nval values = mutableListOf\u003cAny\u003e()\nvar isFinished = false\n\nobservable\u003cAny\u003e { emitter -\u003e\n    // Background job\n}\n    .subscribeOn(ioScheduler)\n    .observeOn(mainScheduler)\n    .threadLocal()\n    .doOnBeforeNext { values += it } // Callback is not frozen, we can update the mutable list\n    .doOnBeforeFinally { isFinished = true } // Callback is not frozen, we can change the flag\n    .subscribe()\n```\n\nSet `isThreadLocal` flag to `true` in `subscribe` operator:\n\n```kotlin\nval values = mutableListOf\u003cAny\u003e()\nvar isComplete = false\n\nobservable\u003cAny\u003e { emitter -\u003e\n    // Background job\n}\n    .subscribeOn(ioScheduler)\n    .observeOn(mainScheduler)\n    .subscribe(\n        isThreadLocal = true,\n        onNext = { values += it }, // Callback is not frozen, we can update the mutable list\n        onComplete = { isComplete = true } // Callback is not frozen, we can change the flag\n    )\n```\n\nIn both cases subscription (`subscribe` call) **must** be performed on the Main thread.\n\n\u003c/details\u003e\n\n## Coroutines interop\n\nThis functionality is provided by the `coroutines-interop` module. Please mind some [known problems](https://github.com/Kotlin/kotlinx.coroutines/blob/native-mt/kotlin-native-sharing.md#known-problems) with multi-threaded coroutines on Kotlin/Native.\n\n### Examples\n\n```kotlin\nval flow: Flow\u003cInt\u003e = observableOf(1, 2, 3).asFlow()\nval observable: Observable\u003cInt\u003e = flowOf(1, 2, 3).asObservable()\n```\n\n```kotlin\nfun doSomething() {\n    singleFromCoroutine { getSomething() }\n        .subscribe { println(it) }\n}\n\nsuspend fun getSomething(): String {\n    delay(1.seconds)\n    return \"something\"\n}\n```\n\n```kotlin\nval defaultScheduler = Dispatchers.Default.asScheduler()\nval computationDispatcher = computationScheduler.asCoroutineDispatcher()\n```\n\n## Subscription management with DisposableScope\n\nReaktive provides an easy way to manage subscriptions: [DisposableScope](https://github.com/badoo/Reaktive/blob/master/reaktive/src/commonMain/kotlin/com/badoo/reaktive/disposable/scope/DisposableScope.kt).\n\nTake a look at the following examples:\n\n```kotlin\nval scope =\n    disposableScope {\n        observable.subscribeScoped(...) // Subscription will be disposed when the scope is disposed\n\n        doOnDispose {\n            // Will be called when the scope is disposed\n        }\n\n        someDisposable.scope() // `someDisposable` will be disposed when the scope is disposed\n    }\n\n// At some point later\nscope.dispose()\n```\n\n```kotlin\nclass MyPresenter(\n    private val view: MyView,\n    private val longRunningAction: Completable\n) : DisposableScope by DisposableScope() {\n\n    init {\n        doOnDispose {\n            // Will be called when the presenter is disposed\n        }\n    }\n\n    fun load() {\n        view.showProgressBar()\n\n        // Subscription will be disposed when the presenter is disposed\n        longRunningAction.subscribeScoped(onComplete = view::hideProgressBar)\n    }\n}\n\nclass MyActivity : AppCompatActivity(), DisposableScope by DisposableScope() {\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n\n        MyPresenter(...).scope()\n    }\n\n    override fun onDestroy() {\n        dispose()\n\n        super.onDestroy()\n    }\n}\n```\n\n## Reaktive and Swift interoperability\n\nPlease see the corresponding documentation page: [Reaktive and Swift interoperability](docs/SwiftInterop.md).\n\n## Plugins\n\nReaktive provides Plugin API, something similar to [RxJava plugins](https://github.com/ReactiveX/RxJava/wiki/Plugins). The Plugin API provides a way to decorate Reaktive sources. A plugin should implement the [ReaktivePlugin](https://github.com/badoo/Reaktive/blob/master/reaktive/src/commonMain/kotlin/com/badoo/reaktive/plugin/ReaktivePlugin.kt) interface, and can be registered using the `registerReaktivePlugin` function and unregistered using the `unregisterReaktivePlugin` function.\n\n```kotlin\nobject MyPlugin : ReaktivePlugin {\n    override fun \u003cT\u003e onAssembleObservable(observable: Observable\u003cT\u003e): Observable\u003cT\u003e =\n        object : Observable\u003cT\u003e {\n            private val traceException = TraceException()\n\n            override fun subscribe(observer: ObservableObserver\u003cT\u003e) {\n                observable.subscribe(\n                    object : ObservableObserver\u003cT\u003e by observer {\n                        override fun onError(error: Throwable) {\n                            observer.onError(error, traceException)\n                        }\n                    }\n                )\n            }\n        }\n\n    override fun \u003cT\u003e onAssembleSingle(single: Single\u003cT\u003e): Single\u003cT\u003e =\n        TODO(\"Similar to onAssembleSingle\")\n\n    override fun \u003cT\u003e onAssembleMaybe(maybe: Maybe\u003cT\u003e): Maybe\u003cT\u003e = \n        TODO(\"Similar to onAssembleSingle\")\n\n    override fun onAssembleCompletable(completable: Completable): Completable =\n        TODO(\"Similar to onAssembleSingle\")\n\n    private fun ErrorCallback.onError(error: Throwable, traceException: TraceException) {\n        if (error.suppressedExceptions.lastOrNull() !is TraceException) {\n            error.addSuppressed(traceException)\n        }\n        onError(error)\n    }\n\n    private class TraceException : Exception()\n}\n```\n\n## Samples:\n\n* [MPP module](https://github.com/badoo/Reaktive/tree/master/sample-mpp-module)\n* [Android app](https://github.com/badoo/Reaktive/tree/master/sample-android-app)\n* [iOS app](https://github.com/badoo/Reaktive/tree/master/sample-ios-app)\n* [JavaScript browser app](https://github.com/badoo/Reaktive/tree/master/sample-js-browser-app)\n* [Linux x64 app](https://github.com/badoo/Reaktive/tree/master/sample-linuxx64-app)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbadoo%2Freaktive","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbadoo%2Freaktive","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbadoo%2Freaktive/lists"}