# RxAndroid: the Looper scheduler that connects RxJava 3 to Android's main thread

> RxAndroid is a small set of Android bindings for RxJava 3, centered on a Scheduler that delivers emissions on the main thread or any Looper. It is for teams already using RxJava on Android, not a reason to adopt RxJava in the first place.

**ReactiveX/RxAndroid** — RxJava bindings for Android

- Repository: https://github.com/ReactiveX/RxAndroid
- Stars: 19,917 · Forks: 2,936
- Language: Java
- License: Apache-2.0
- Published: 2026-09-21 · Updated: 2026-09-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/reactivex-rxandroid

## What RxAndroid actually adds to an RxJava Android app

RxJava gives you operators, threading via Schedulers, and a subscription model. It does not know what Android's main thread is. RxAndroid is the bridge: the README describes it as adding "the minimum classes to RxJava that make writing reactive components in Android applications easy", and the concrete piece is a Scheduler that schedules work on the main thread or on any Looper you hand it.

That narrow scope is the point. If your app already uses RxJava 3 for network calls, database reads or event streams, and you need the result to land on the UI thread, RxAndroid supplies the scheduler you call in observeOn. Without it you would be posting to a Handler yourself inside every subscriber, which is exactly the boilerplate the library removes.

It is not a UI toolkit, not a lifecycle library, and not a replacement for RxJava. The repository layout reflects that: a rxandroid/ module, a sample-app/ module for runnable examples, and build files. There is no Android View binding layer here.

## How the main thread and Looper schedulers work

Android applications run a message loop per thread, and the UI thread has a Looper that processes that queue. RxAndroid wraps that mechanism in a Scheduler, so RxJava's threading operators can target it.

The README's first example declares a stream and moves it off the calling thread, then back onto the main thread:

```java
Observable.just("one", "two", "three", "four", "five")
    .subscribeOn(Schedulers.newThread())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(/* an Observer */);
```

The README states that this executes the Observable on a new thread and emits results through onNext on the main thread. The data flow is unchanged from plain RxJava: subscribeOn decides where the subscription and upstream work run, observeOn decides where downstream emissions are delivered. RxAndroid only supplies the destination.

The general case is AndroidSchedulers.from, which takes a Looper and returns a Scheduler bound to it. The README notes that emissions then arrive on whatever thread is running that Looper. That is the useful part for background pipelines: a worker thread with its own Looper can receive emissions without touching the UI thread at all. Note the asymmetry in the README's wording: the first example says the Observable executes on a new thread, while the Looper example says it executes on a new thread and emits on the Looper's thread. Both describe scheduling, not a new execution model.

## Installing rxandroid and observing on the main thread

The README gives the dependency block directly. Note that the group is io.reactivex.rxjava3, not the older io.reactivex.rxjava2 group you may still have in an older module.

```groovy
dependencies {
    implementation 'io.reactivex.rxjava3:rxandroid:3.0.2'
    implementation 'io.reactivex.rxjava3:rxjava:3.1.5'
}
```

The README pairs the two artifacts deliberately and explains why: RxAndroid releases are few and far between, so it recommends depending explicitly on RxJava's latest 3.x version for bug fixes and new features. In other words, the rxandroid artifact does not drag a matching rxjava version along with it as a guarantee, and you should not assume the version numbers are in step. The release history supports the point: 3.0.0 shipped in February 2020, and 3.0.1 and 3.0.2 both landed in November 2022.

For a first real use, take the README's own example and observe on the main thread:

```java
Observable.just("one", "two", "three", "four", "five")
    .subscribeOn(Schedulers.newThread())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(/* an Observer */);
```

The observable emits five strings on a new thread; the subscriber's onNext runs on the main thread, which is where you would touch a View. If you need a different thread, build a scheduler from its Looper instead:

```java
Looper backgroundLooper = // ...
Observable.just("one", "two", "three", "four", "five")
    .observeOn(AndroidSchedulers.from(backgroundLooper))
    .subscribe(/* an Observer */)
```

The README also points to the sample-app/ folder for runnable examples, and to the RxJava Getting Started wiki page for build details. There is no published Homepage field on the repository, so the README and that wiki are where the project directs you.

## Where RxAndroid is the wrong tool

The library is small by design, and that leaves real gaps. It has no lifecycle awareness: nothing here ties a subscription to an Activity or Fragment, so a long-running stream observed on the main thread will keep delivering after the screen is gone unless you dispose it yourself. The README does not document a lifecycle helper, because there is none in the module.

There is also no error-handling policy and no backpressure strategy layered on top of RxJava. If you need those, they live in RxJava, not here, and the README treats RxAndroid as an Android-specific addition rather than a framework.

Version drift is the practical failure mode. Because RxAndroid releases are infrequent, a project that pins only rxandroid and lets the transitive rxjava version float can end up on an older RxJava than its other modules use, producing duplicate classes or NoSuchMethodError at runtime. The README's recommendation to declare rxjava explicitly exists to prevent that.

Finally, if your project has no RxJava code, adding RxAndroid buys you nothing. The main-thread scheduling problem is already solved by Kotlin coroutines with Dispatchers.Main, by Handler and post, or by LiveData and Flow. RxAndroid is a binding for an existing dependency, not a reason to introduce one.

## RxAndroid compared with coroutines and with plain Handler posting

The closest alternative in modern Android work is Kotlin coroutines. The difference is structural rather than cosmetic: coroutines express sequential asynchronous code with suspend functions and structured scopes, so cancellation and lifetime are tied to the scope that launched the work. RxJava and RxAndroid express the same work as a stream of events with operators, and cancellation is a Disposable you hold and call dispose on. If your team writes Kotlin and wants cancellation handled by scope, coroutines are the shorter path.

If you are staying in RxJava, the alternative to RxAndroid is doing the hop yourself: post each result to a Handler attached to the main Looper inside the subscriber. That works, but it moves the threading decision into every subscriber and makes it easy to miss one. AndroidSchedulers.mainThread() centralizes that decision in the observeOn call.

A third option is to keep RxJava for stream composition and use RxAndroid only at the boundary where you must reach the UI thread. That is the usage the README demonstrates, and it is the one that matches the library's size. Nothing in the module tries to own the rest of your architecture.

## Maintenance, releases and the Apache-2.0 licence

The repository is not archived, and its last push was on 2026-08-27, which is recent. That said, the release cadence is slow and the README says so plainly: RxAndroid releases are few and far between, and it recommends tracking RxJava separately for fixes. The published releases tell the same story, with 3.0.0 in February 2020 and both 3.0.1 and 3.0.2 in November 2022.

The upgrade cost is therefore mostly an RxJava cost. When RxJava 3.x moves, you update the rxjava artifact and re-check that the rxandroid artifact you depend on still resolves against it. The README also documents a snapshot path for the development version, io.reactivex.rxjava3:rxandroid:3.1.0-SNAPSHOT, served from Sonatype's snapshots repository, which means adding that repository to your build if you want to track unreleased changes. Snapshots are not a stable dependency target.

The project is licensed under Apache-2.0. The README carries the standard notice: licensed under the Apache License, Version 2.0, distributed on an "AS IS" BASIS, without warranties or conditions of any kind. Apache-2.0 is a permissive licence that permits commercial and closed-source use and requires that you keep the licence and notice. This is a description of the terms in the repository, not legal advice; check your own obligations with counsel if the distinction matters to your product.

## Conclusion

Adopt RxAndroid if your Android codebase already depends on RxJava 3 and you need emissions on the main thread or on a specific Looper; the README's own advice to pin a recent RxJava version alongside it is the first thing to verify in your build. Do not adopt it as a reason to bring RxJava into a project that has no reactive code, and do not expect it to replace structured concurrency for new work. Before merging, confirm that the rxandroid artifact and your rxjava artifact share the io.reactivex.rxjava3 group and that your Gradle build resolves both.

## FAQ

### What is the difference between RxJava and RxAndroid?

RxJava provides the reactive types and operators; RxAndroid adds Android-specific bindings on top of it. The README describes the module as adding the minimum classes needed, specifically a Scheduler that schedules on the main thread or any given Looper.

### What is RxJava used for in Android development?

In the usage this project documents, RxJava composes asynchronous work as a stream and lets you choose where subscription and emission happen. RxAndroid supplies the Android side of that choice, so results can be observed on the main thread or on a specific Looper.

### How do I add the rxandroid dependency to a Gradle build?

The README shows an implementation line for io.reactivex.rxjava3:rxandroid:3.0.2, paired with an explicit implementation line for io.reactivex.rxjava3:rxjava:3.1.5. It recommends declaring RxJava yourself because RxAndroid releases are infrequent.

### How does RxAndroid get results onto the main thread?

You call observeOn(AndroidSchedulers.mainThread()) in the chain. The README states that the Observable executes on a new thread and emits results through onNext on the main thread.

### Can RxAndroid observe on a thread other than the main thread?

Yes. AndroidSchedulers.from takes a Looper and returns a Scheduler bound to it, and the README states that emissions then arrive on whatever thread is running that Looper.

## Sources

- [Issues](https://github.com/ReactiveX/RxAndroid/issues)
- [License: Apache-2.0](https://github.com/ReactiveX/RxAndroid/blob/3.x/LICENSE)
- [ReactiveX/RxAndroid on GitHub](https://github.com/ReactiveX/RxAndroid)
- [README](https://github.com/ReactiveX/RxAndroid/blob/3.x/README.md)
- [Releases](https://github.com/ReactiveX/RxAndroid/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/reactivex-rxandroid
