Guide and execute the migration of asynchronous code from RxJava to Kotlin Coroutines and Flow. Use this skill when a user asks to convert RxJava (Observables, Singles, Completables, Subjects) to Coroutines (suspend functions, Flows, StateFlows).
65
78%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Fix and improve this skill with Tessl
tessl review fix ./.github/skills/migration/rxjava-to-coroutines-migration/SKILL.mdA specialized skill designed to safely and idiomatically refactor Android or Kotlin codebases from RxJava to Kotlin Coroutines and Flow.
When migrating RxJava components to Kotlin Coroutines, use the following standard mappings:
Single<T> -> suspend fun ...(): T
Maybe<T> -> suspend fun ...(): T?
Completable -> suspend fun ...()
Observable<T> -> Flow<T>
Flowable<T> -> Flow<T>
PublishSubject<T> -> MutableSharedFlow<T>
MutableSharedFlow(extraBufferCapacity = ...) if buffering is needed.BehaviorSubject<T> -> MutableStateFlow<T>
ReplaySubject<T> -> MutableSharedFlow<T>(replay = N)
Schedulers.io() -> Dispatchers.IOSchedulers.computation() -> Dispatchers.DefaultAndroidSchedulers.mainThread() -> Dispatchers.MainsubscribeOn and observeOn are typically replaced by withContext(Dispatcher) or flowOn(Dispatcher) for Flows.map -> mapfilter -> filterflatMap -> flatMapMerge (concurrent) or flatMapConcat (sequential)switchMap -> flatMapLatestdoOnNext / doOnSuccess -> onEachonErrorReturn / onErrorResumeNext -> catch { emit(...) }startWith -> onStart { emit(...) }combineLatest -> combinezip -> zipdelay -> delay (suspend function) or onEach { delay(...) }subscribe() -> collect {} (for Flows) or direct invocation (for suspend functions) inside a CoroutineScope.Disposable.dispose() -> Job.cancel()CompositeDisposable.clear() -> Cancel the parent CoroutineScope or Job.suspend functions for one-shot operations, and Flow for streams.map or onEach block..subscribe(...) with launch { ... } and .collect { ... } in the ViewModel or Presenter. Ensure the launch is tied to the correct lifecycle scope (e.g., viewModelScope).onError blocks with try/catch around suspend functions, or .catch { } operators on Flows..subscribeOn() and .observeOn(). Use withContext where necessary, or .flowOn() to change the context of the upstream flow.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)
}
}suspend functions instead of Flow unless you actually have a stream of multiple values over time. Single and Completable almost always become suspend functions.StateFlow in ViewModels to expose state to the UI instead of BehaviorSubject or LiveData.repeatOnLifecycle or flowWithLifecycle in the UI layer when collecting Flows to avoid background work when the view is not visible.82900ea
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.