RxJava与Coroutine对比

21 篇文章 2 订阅
14 篇文章 1 订阅

RxJava作为流式异步框架早已被广泛熟知和使用,如今Kotlin又为我们提供了一个新的选择Coroutine、在一些场景下可以替代RxJava的使用。本文通过比较两者在使用上的不同,希望让RxJava的使用者们能了解到Coroutine的优点,可以作为一个新的选项在项目中应用。本文适合以下读者:

  • 有Kotlin的使用经验
  • 有RxJava(RxKotlin)的使用经验
  • 有兴趣尝试Coroutine

Coroutine与Rx的对标

Flow出来以前,Coroutine不能用来Stream数据,所以无法替代Rx。Flow的出现弥补了填补了短板,似的Coroutine已经基本上可以完全替代Rx的使用。Rx中强大的操作符在Flow中也得到了支持,例如mapfilterscanretry等。Rx的Observable类型可以使用Flow替代,Rx的SingleCompletable可以更简单的Coroutine处理方式替代:

一次性数据Stream数据(Cold)Stream数据(Hot)
RxJavaSingle/Maybe/CompletableObservableSubject
CoroutineSuspend FunctionsFlowChannel

通过上表可以简单了解Rx与Coroutine在数据处理方面分别用到哪些类


Single


Rx

Rx中使用Single处理只发射一次的数据时使用Single,例如一个单次DB的操作或者Http请求等

fun getRequest(): Single<String> {
    return Single.create<String> { emitter ->
        // ...
        emitter.onSuccess(body.message)
    }
}

Coroutine

Coroutine可以使用suspend函数,像普通函数一样进行任何处理后同步返回结果,非常清爽:

suspend fun getRequest(): String{
    // 耗时处理
    return body.message
}

需要注意Single是Cold Stream的,当订阅时才触发,suspend函数则不需要,所以需要Cold触发的场景,要借助Coroutine的Channel


Callback转Single


Rx

有时我们会将一个Callback转成Rx的Single

fun getRequest(): Single<String> {
    return Single.create<String> { emitter ->
        val callback = object: Callback {
            override fun onNextValue(value: String) {
                emitter.onSuccess(value)
            }
            override fun onApiError(cause: Throwable) {
                emitter.onFailure(Exception("API Error", cause))
            }
        }
    }
}

Coroutine

同样,我们可以将一个Callback转成Coroutine的suspend函数:suspendCoroutine调用后函数被挂起,再通过resume或者resumeWithException恢复执行

suspend fun getMessages(): String {
    return suspendCoroutine<String> { coroutine ->
        val callback = object: Callback {
            override fun onNextValue(value: String) {
                coroutine.resume(value)
            }
            override fun onApiError(cause: Throwable) {
                coroutine.resumeWithException(Exception("API Error", cause))
            }
        }
    }
}

Completable


Rx

Rx不返回数据直接onComplete时,使用Completable

fun updateRequest(): Completable {
    return Completable.create { emitter ->
        // ...
        emitter.onComplete()
    }
}

Coroutine

不返回数据直接return

suspend fun updateRequest() {
    // ...
    return
}

Observable.just()


Rx

Observable.just()用来发射一次性数据,实际相当于Single

fun getMessage(): Observable<String> {
    return Observable.just("rxData")
}

Coroutine

可以使用flowOf替换Observable.just()

fun getMessage(): Flow<String> {
    return flowOf("flowData")
}

Observable.create()


Rx

当需要发射多个数据时,使用Observable.create()

fun getMessages(): Observable<String> {
    return Observable.create { observer ->
        for(/*循环多次*/) {
            observer.onNext("rxData")
        }
        observer.onComplete()
    }
}

Coroutine

flow的block退出执行之前会自动调用completed

fun getMessages(): Flow<String> {
    return flow {
        repeat(/*循环多次*/) {
            emit("flowData")
        }
    }
}

Callback转Observable


Rx

可以将一个多次回调的Callback转成一个Observable,通过onNext将以Stream的形式发送数据

fun getMessages(): Observable<String> {
    return Observable.create { observer ->
        val callback = object: Callback {
            override fun onNextValue(value: String) {
                observer.onNext(value)
            }
            override fun onApiError(cause: Throwable) {
                observer.onError(Exception("API Error", cause))
            }
            override fun onComplete() = observer.onComplete()
        }
    }.doFinally {
    	//stream结束时的后处理
    }
}

Coroutine

fun getMessages(): Flow<String> {
    return callbackFlow {
        val callback = object: Callback {
            override fun onNextValue(value: String) {
                offer(value)
            }
            override fun onApiError(cause: Throwable) {
                cancel(Exception("API Error", cause))
            }
            override fun onComplete() = channel.close()
        }
    }
    awaitClose {
    	//stream结束时的后处理
    }
    // 注意awaitClose{...}之后不应该有其他代码
    /* End */
    
}

BehaviorSubject()


Rx

BehaviorSubject()是持有一个最近数据的Hot Stream

class SampleClass {
    private val behaviorSubject: BehaviorSubject<Int> = BehaviorSubject.create(0)
}

Coroutine

class SampleClass {
    private val channel: Channel<Int> = Channel(Channel.CONFLATED)
}

ReplaySubject()


Rx

class SampleClass {
    private val replaySubject: ReplaySubject<Int> = ReplaySubject.create()
}

Coroutine

class SampleClass {
    private val channel: Channel<Int> = Channel(Channel.UNLIMTED)
}

Subscribe()

Rx

Single.just(1).subscribeBy(
    onNext = { v ->
        // ...
    }
)

Coroutine(suspend方式)

suspend fun sample(): Int {
    return 1
}

//...

launch {
    sample() // 想调用普通函数一样
}
Coroutine(Flow方式)
fun getFlow(): Flow<Int> = flowOf(1)

//...

launch {
    getFlow().collect{ v ->
        // ...
    }
}

Coroutine(Channel方式)

fun getChannel(): ReceiveChannel<Int> {
    return this.channel
} 

//...

launch {
    getChannel()
        .consumeAsFlow() // 将Hot Stream转成 Cold Stream, 相当于flow
        .collect { v ->
            // ...
        }
}

串行处理


Rx

fun getMessages(): Observable<String> {
    return Observable.create<String> { observer ->
        val callback = object: Callback {
            override fun onNextValue(value: String) {
                observer.onNext(value)
            }
            override fun onApiError(cause: Throwable) {
                observer.onError(Exception("API Error", cause))
            }
            override fun onComplete() = observer.onComplete()
        }
    }.doFinally {/*...*/}
}

fun getRequest(url: String): Single<String> {
    return Single.create { emitter ->
        // http请求
        emitter.onSuccess(message.body)
    }
}

fun insertDB(body: String): Completable {
    return Completable.create { emitter ->
        // 更新DB
        emitter.onComplete()
    }
}

//...

getMessages()
    .flatMapSingle { getRequest(it) }
    .flatMapCompletable { insertDB(it) }
    .subscribeBy(onComplete = {})

Coroutine

fun getMessages(): Flow<String> {
    return callbackFlow {
        val callback = object : Callback {
            override fun onNextValue(value: String) {
                offer(value)
            }
            override fun onApiError(cause: Throwable) {
                cancel(Exception("API Error", cause))
            }
            override fun onComplete() = channel.close()
        }
    }
    awaitClose {/*...*/}
}

suspend fun getRequest(url: String): String {
    // http请求
    return message.body
}

suspend fun insertDB(body: String) {
    // 插入DB
    return
}

//...
launch {
    getMessages().onEach { url ->
        val body = getRequest(rul)
        insertDB(body)
    }.collect {}
}

并行处理


Rx

通过zip同时发起两个Http请求

fun getHogeRequest(): Single<String> {
    return Single.create { emitter ->
        // HTTP请求
        emitter.onSuccess(message.body)
    }
}

fun getFugaRequest(): Single<String> {
    return Single.create { emitter ->
        // HTTP请求
        emitter.onSuccess(message.body)
    }
}

//...
Single.zip(getHogeRequest(), 
			getFugaRequest()).
			subscribeBy(
				onNext = {
				 	v: Pair<String, String> ->
				}
			)

Coroutine

async同时启动两个Http请求,通过awaitAll()等待两个请求返回结果

suspend fun getHogeRequest(): String {
    // HTTP请求
    return message.body
}

suspend fun getFugaRequest(): String {
    // HTTP请求
    return message.body
}

//...

launch {
    val resultList: List<String> = listOf(
    	async{ getHogeRequest() },
    	async{ getFugaRequest() })
    	.awaitAll()
}

Dispose


Rx

val disposable = hogeObservable().subscribeBy(onNext = {})

disposable.dispose()

Coroutine

val job = launch {
    hogeFlow.collect {}
}

job.cancel()

总结


最后总结一下Coroutine替代Rx时的注意点

  • Single和Completable可以使用suspend fun替代
  • Observable可以使用Flow替代
  • BehaviorSubject等Subject可以使用Channel替代

RxJava中的各个类型,无论是Observable、Single还是Subject,其支持的API都差不多:都支持同样的操作符,都可以进行subscribe。
反观Coroutine,suspend函数、Flow或者Channel 虽然都是基于函数挂起的原理运行,但是支持的API确大相径庭,这可能是Coroutine使用中的一点门槛。另外,还需要需要理解CoroutineScopeCoroutineContext等概念,这都是顺利使用Coroutine的基础。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

fundroid

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值