install
source · Clone the upstream repo
git clone https://github.com/ComeOnOliver/skillshub
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/ComeOnOliver/skillshub "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/new-silvermoon/awesome-android-agent-skills/rxjava-to-coroutines-migration" ~/.claude/skills/comeonoliver-skillshub-rxjava-to-coroutines-migration && rm -rf "$T"
manifest:
skills/new-silvermoon/awesome-android-agent-skills/rxjava-to-coroutines-migration/SKILL.mdsource content
RxJava to Kotlin Coroutines Migration Skill
A specialized skill designed to safely and idiomatically refactor Android or Kotlin codebases from RxJava to Kotlin Coroutines and Flow.
Migration Mapping Guide
When migrating RxJava components to Kotlin Coroutines, use the following standard mappings:
1. Base Types
->Single<T>suspend fun ...(): T- A single asynchronous value.
->Maybe<T>suspend fun ...(): T?- A single asynchronous value that might not exist.
->Completablesuspend fun ...()- An asynchronous operation that completes without a value.
->Observable<T>Flow<T>- A cold stream of values.
->Flowable<T>Flow<T>- Coroutines Flow natively handles backpressure.
2. Subjects to Hot Flows
->PublishSubject<T>MutableSharedFlow<T>- Broadcasts events to multiple subscribers. Use
if buffering is needed.MutableSharedFlow(extraBufferCapacity = ...)
- Broadcasts events to multiple subscribers. Use
->BehaviorSubject<T>MutableStateFlow<T>- Holds state and emits the current/latest value to new subscribers. Requires an initial value.
->ReplaySubject<T>MutableSharedFlow<T>(replay = N)- Replays the last N emitted values to new subscribers.
3. Schedulers to Dispatchers
->Schedulers.io()Dispatchers.IO
->Schedulers.computation()Dispatchers.Default
->AndroidSchedulers.mainThread()Dispatchers.Main- Context Switching:
andsubscribeOn
are typically replaced byobserveOn
orwithContext(Dispatcher)
for Flows.flowOn(Dispatcher)
4. Operators
->mapmap
->filterfilter
->flatMap
(concurrent) orflatMapMerge
(sequential)flatMapConcat
->switchMapflatMapLatest
/doOnNext
->doOnSuccessonEach
/onErrorReturn
->onErrorResumeNextcatch { emit(...) }
->startWithonStart { emit(...) }
->combineLatestcombine
->zipzip
->delay
(suspend function) ordelayonEach { delay(...) }
5. Execution and Lifecycle
->subscribe()
(for Flows) or direct invocation (for suspend functions) inside acollect {}
.CoroutineScope
->Disposable.dispose()Job.cancel()
-> Cancel the parentCompositeDisposable.clear()
orCoroutineScope
.Job
Execution Steps
- Analyze the RxJava Chain: Identify the source type (Single, Observable, etc.), operators used, and where the subscription happens.
- Convert the Source: Change the return type in the repository or data source layer first. Convert to
functions for one-shot operations, andsuspend
for streams.Flow - Rewrite Operators: Translate the RxJava operators to their Flow or Coroutine equivalents. Note that many RxJava operators can simply be replaced by standard Kotlin collection/sequence operations inside a
ormap
block.onEach - Update the Subscription: Replace
with.subscribe(...)
andlaunch { ... }
in the ViewModel or Presenter. Ensure the launch is tied to the correct lifecycle scope (e.g.,.collect { ... }
).viewModelScope - Handle Errors: Replace
blocks withonError
around suspend functions, ortry/catch
operators on Flows..catch { } - Handle Threading: Remove
and.subscribeOn()
. Use.observeOn()
where necessary, orwithContext
to change the context of the upstream flow..flowOn()
Example Transformation
RxJava:
fun getUser(id: String): Single<User> { ... } disposable.add( getUser("123") .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe({ user -> view.showUser(user) }, { error -> view.showError(error) }) )
Coroutines/Flow:
suspend fun getUser(id: String): User { ... } // Internally uses withContext(Dispatchers.IO) if needed viewModelScope.launch { try { val user = getUser("123") view.showUser(user) } catch (e: Exception) { view.showError(e) } }
Best Practices
- Favor Suspend Functions: Default to
functions instead ofsuspend
unless you actually have a stream of multiple values over time.Flow
andSingle
almost always becomeCompletable
functions.suspend - State Handling: Use
in ViewModels to expose state to the UI instead ofStateFlow
orBehaviorSubject
.LiveData - Lifecycle Awareness: Use
orrepeatOnLifecycle
in the UI layer when collecting Flows to avoid background work when the view is not visible.flowWithLifecycle