是該繼續Rxjava,還是應該試試Kotlin的協程?你怎麼選

0.前言

協程以前一直是Kotlin作為實驗性的一個庫,前些日子發現1.3版本的kotlin relese了協程,所以就找時間研究了一下,本來早就想寫這篇文章了,但是因為離職換工作的原因,遲遲未能動筆,這兩天終於算搞完了,記錄一下我對協程的一些理解。

是該繼續Rxjava,還是應該試試Kotlin的協程?你怎麼選

1.什麼是協程

1.1協程定義

我第一次接觸協程是在python的教程裡,這裡拿來用來解釋一下:子程序,或者稱為函數,在所有語言中都是層級調用,比如A調用B,B在執行過程中又調用了C,C執行完畢返回,B執行完畢返回,最後是A執行完畢。所以子程序調用是通過棧實現的,一個線程就是執行一個子程序。子程序調用總是一個入口,一次返回,調用順序是明確的。而協程的調用和子程序不同。協程看上去也是子程序,但執行過程中,在子程序內部可中斷,然後轉而執行別的子程序,在適當的時候再返回來接著執行。注意,在一個子程序中中斷,去執行其他子程序,不是函數調用,有點類似CPU的中斷。

1.2協程和線程的關係

協程和線程,都能用來實現異步調用,但是這兩者之間是有本質區別的

(1)協程是編譯器級別的,線程是系統級別的。協程的切換是由程序來控制的,線程的切換是由操作系統來控制的。

(2)協程是協作式的,線程是搶佔式的。協程是由程序來控制什麼時候進行切換的,而線程是有操作系統來決定線程之間的切換的。

(3)一個線程可以包含多個協程。

(4)Java中,多線程可以充分利用多核cpu,協程是在一個線程中執行。

(5)協程適合io密集型的程序,多線程適合計算密集型的程序(適用於多核cpu的情況)。當你的程序大部分是文件讀寫操作或者網絡請求操作的時候,這時你應該首選協程而不是多線程,首先這些操作大部分不是利用cpu進行計算而是等待數據的讀寫,其次因為協程執行效率較高,子程序切換不是線程切換,是由程序自身控制,因此,沒有線程切換的開銷,和多線程比,線程數量越多,協程的性能優勢就越明顯。

(6)使用協程可以順序調用異步代碼,避免回調地獄。

2.簡單用法

這裡我打算模仿一個網絡請求,點擊button發送網絡請求,顯示一個progressbar打轉,返回結果後一個textview顯示結果並隱藏progressbar

先看一下佈局文件


<framelayout> xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<textview> android:id="@+id/timeTV"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<button> android:id="@+id/sendBT"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="SEND"
android:layout_gravity="center"/>
<progressbar> android:layout_gravity="center"
android:visibility="gone"
android:id="@+id/loadingPB"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
/<progressbar>/<button>/<textview>/<framelayout>

一個Button,一個TextView,一個ProgressBar

class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
sendBT.setOnClickListener {
coroutineSend()
}
}
private fun coroutineSend() {
val uiScope = CoroutineScope(Dispatchers.Main)
uiScope.launch {
loadingPB.visibility = View.VISIBLE
val deffer = async(Dispatchers.Default) {
getCoroutineResult()
}
val coroutineResult = deffer.await()
timeTV.text = "get $coroutineResult"
loadingPB.visibility = View.GONE
}
}
private suspend fun getCoroutineResult(): String {
delay(9000L)
return "coroutine result"
}

}

首先創建了一個CoroutineScope,所有協程都運行在CoroutineScope中,創建CoroutineScop中傳入參數Dispatchers.Main,這是一個協程調度器,它確定了相應的協程在執行時使用一個或多個線程。協程調度器可以將協程的執行侷限在指定的線程中,調度它運行在線程池中或讓它不受限的運行。 調用launch,就啟動了一個協程,launch方法會返回一個job,調用cancel方法可以取消這個協程的進行。可以看到在協程裡我們先展示出loadingPB,然後調用async又啟動一個協程,同時使用Dispatchers.Default這個協程調度器,它將使協程在執行時使用一個DefaultDispatcher-worker-1線程,這裡為什麼使用async而沒有使用launch,是因為async會返回一個Deferred對象,調用其await方法可以阻塞執行流等到協程執行完畢返回結果,這樣可以得到一個返回值,在這個async創建的協程裡使用了使用了suspend方法

private suspend fun getCoroutineResult(): String {
delay(9000L)
return "coroutine result"
}

先休眠9秒鐘,然後返回一個字符串,注意這裡這個delay也是suspend方法,一個suspend方法只能在協程或者suspend方法裡調用。關於協程還有一些其他的創建和使用方法,有興趣的可以去看看官方教程。

3.Rxjava VS 協程

協程相對RxJava有什麼優點呢?

(1)RxJava堆棧可讀性查,一旦出現問題,堆棧信息爆炸,難以定位問題,而協程就可以避免這個問題

(2)協程用同步的方式寫異步的代碼,美好了生活,方便代碼閱讀。

(3)協程學習曲線比較平坦,相對於RxJava,協程對初學者更易於學習。

是該繼續Rxjava,還是應該試試Kotlin的協程?你怎麼選

是該繼續Rxjava,還是應該試試Kotlin的協程?你怎麼選

是該繼續Rxjava,還是應該試試Kotlin的協程?你怎麼選

是該繼續Rxjava,還是應該試試Kotlin的協程?你怎麼選

是該繼續Rxjava,還是應該試試Kotlin的協程?你怎麼選

是該繼續Rxjava,還是應該試試Kotlin的協程?你怎麼選

是該繼續Rxjava,還是應該試試Kotlin的協程?你怎麼選

為了讓學習變得輕鬆、高效,今天給大家免費分享一套阿里p7架構師傳授的一套教學資源。幫助大家在成為架構師的道路上披荊斬棘。

詳細講解了(高級UI、性能優化、熱修復、熱更新、NDK、Kotlin進階、混合式開發(ReactNative+Weex))等成為架構師必備的內容!

關注我:私信回覆【學習】免費獲取Android進階資料!


分享到:


相關文章: