Coroutines和Rxjava异步编程对比

原文地址:https://medium.com/@manuelvicnt/coroutines-and-rxjava-an-asynchronicity-comparison-part-1-asynchronous-programming-e726a925342a

这一系列的文章将会用来进行Coroutines和Rxjava在解决异步编程方面的对比。

案例一:为一个快速启动的App创建复杂的对象

如果希望自己的应用程序能够快速启动,那么处理创建对象的过程非常重要,如果对于复杂的对象创建发生在UI线程的话,将会引起丢帧的情况。
所以对于这种情况我们我们需要在后台线程中做这些操作。

RxJava

我们如何使用Rxjava来初始化我们想要的对象?

fun initializeObjectsAsync(): Completable{
  return Completable.create{ emitter -> 
    try{
      heavyInitialzation()
      if(!emitter?.isDisposed){
        emitter?.onComplete()
      }
    }catch(e:Exception){
      if (!emitter?.isDisposed) {
        emitter?.onError(e)
      }
    }
  }
}

正如你所见,我们创建了一个方法返回Completable对象,在方法内部,我们通过Completable.create创建了一个Completable,他将使用一个发射器(这个对象是可以被订阅的)。
执行完复杂的初始化后,我们将通知成功,如果有错误发生,我们将通知所发生的错误,这是因为发射器的类型是CompletableEmitter,而onComplete和onError是可用于将结果传递给订阅服务器的方法。

另一种方法是使用Completable.fromCallable()

fun initializeObjectsAsync(): Completable {
    return Completable.fromCallable({
            heavyInitialization()
    })
}

我们如何消费该方法呢?

Observables和Completables在Rxjava中都是冷冰冰的,这意味着我们只有订阅时,才会执行Completable.create中的代码,需要记住的是,每次订阅都会执行。
我们必须订阅我们在上面创建的initializeObjectsAsync函数中创建的Completable。

fun initializeObjects() {
    initializeObjectsAsync()
        .subscribeOn(Schedulers.computation())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe({
            // The initialization succeeded!
            // We can perform UI changes here 
        }, {
            // An Error occurred!
        })
}

我们如何告诉RxJava我们想要在后台线程中执行初始化操作?我们使用subscribeOn操作符来告诉RxJava,我们希望Completable.create中的代码能够在后台线程上执行。
当执行完毕时,我们需要对UI进行更新操作,我们可以使用observableOn操作符来告诉RxJava我们想在Android主线程中监听结果。

只有当你订阅Completable时,才会执行Completable.create中的代码

定义线程之后,我们需要启动订阅才能在完成时接收到通知,使用.subscribe方法来做到这一点,我们需要传递两个代码块,一个是接收成功的方法,一个是接收失败的方法。
如果想要上述代码被执行,我们需要创建一个Android Activity,例如,我们可以在onCreate方法中调用这个方法。

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    initializeObjects()
}

Kotlin Coroutines

使用Coroutines的话会更简单,从概念上讲,协程和线程类似,我们可以编写在特定线程上运行的代码。

CoroutineBuilder是一个可以用来创建Coroutine的方法,运行一段代码,并以某种形式访问其结果,CoroutineBuilder的例子有:launch,async,runBlocking...

假设我们要像在onCreate方法中那样调用heavyInitialization方法,我们可以使用CoroutineBuilder启动创建一个Coroutine,并在要运行的代码块执行大量初始化的代码。

fun initializeObjects() {
    launch(CommonPool) {
        heavyInitialization()
    }
}

CommonPool类似于RxJava中的Schedulers.computation(),将会在后台线程中运行代码。
让我们模仿RxJava中构建的例子,我们想知道它什么时候完成初始化复杂对象和错误的处理。

fun initializeObjects() {
    launch(CommonPool) {
        try {
            heavyInitialization()
            // The initialization succeeded!
            withContext(UI) {
                // We can perform UI changes here
            }
        } catch (e: Exception) {
            // An Error occurred!
        }
    }
}

由于Coroutine中的代码被顺序执行,因此在初始化成功代码将接着初始化的代码执行。
和以前一样,我们可以将调用封装在try catch块中进行错误处理。

我们如何切换UI线程来通知UI更新,这里有一个方法withContext,使用另一个CoroutineContext来运行其中的代码块。

我们在示例中看到的CoroutineContext不是标准Kotlin Coroutines库中的一部分,由于它是Android专用的,因此可以在其他库中使用:org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version

示例二:在后台线程执行斐波那契数列

区别于在后台执行一些操作,我们也需要返回一个值,现在我们在用户点击按钮是计算斐波那契数列。

想象一下我们使用下面的代码来计算斐波那契数列:

private fun fib(n: Long): Long {        
    return if (n <= 1) n        
    else fib(n - 1) + fib(n - 2)    
}

我们如何在后台线程中计算他并且返回结果呢?

RxJava

这次我们使用Single来实现。

fun fibonacciAsync(number: Long): Single = 
    Single.create({ emitter ->
            val result = fib(number) 
            if (!emitter?.isDisposed) {       
                 emitter.onSuccess(result)
            }
})

你也可以使用fromCallback方法:

fun fibonacciAsync(number: Long): Single = 
    Single.fromCallable({
        return fib(number)
    })

我们把我们想要的数字作为该函数的参数传递,这也将在Single.create代码块中使用,例如,我们可以从EditText中获取该号码。

@OnClick(R.id.my_button)
fun onButtonClicked() { 
    fibonacciAsync(numberInputEditText.text.toString().toLong())
       .subscribeOn(Schedulers.computation())
       .observeOn(AndroidSchedulers.mainThread())
       .subscribe({ fibonacciNumber -> 
           //Update UI with the result 
           myTextView.text = fibonacciNumber
       },{
           // Error happened
       })
}

用户每次点击按钮,我们都将计算一个新的斐波那契数值,如果用户修改了Edittext中的值,结果也将会变得不同。

Kotlin Coroutines

这个示例将会和上面的一样简单,当用户点击按钮,我们就开启一个Coroutine来计算斐波那契数列。

@OnClick(R.id.my_button)
fun onButtonClicked(){
  launch(CommonPool) {
    val result = fibonacciAsync (
      numberInputEditText.text.toString().toLong()
    )
    withContext(UI){
      fibonacciResultTextView.text = result
    }
  }
}

下篇文章将介绍取消执行。
如何取消Observable和Coroutine。不要错过。

你可能感兴趣的:(Coroutines和Rxjava异步编程对比)