忘記Rxjava吧,你應該試試Kotlin的協程

0.前言

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

1.什麼是協程

1.1協程定義

我第一次接觸協程是在python的教程裏,當時廖雪峯在其中的解釋仍是不錯的,這裏拿來用來解釋一下:子程序,或者稱爲函數,在全部語言中都是層級調用,好比A調用B,B在執行過程當中又調用了C,C執行完畢返回,B執行完畢返回,最後是A執行完畢。因此子程序調用是經過棧實現的,一個線程就是執行一個子程序。子程序調用老是一個入口,一次返回,調用順序是明確的。而協程的調用和子程序不一樣。協程看上去也是子程序,但執行過程當中,在子程序內部可中斷,而後轉而執行別的子程序,在適當的時候再返回來接着執行。注意,在一個子程序中中斷,去執行其餘子程序,不是函數調用,有點相似CPU的中斷。python

看這個圖,協程就是這樣,在一個線程中順序執行的,先執行一段程序,這裏用continuation表示,而後遇到suspension point是,程序懸掛,進行下一個continuation子程序的運行。android

1.2協程和線程的關係

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

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

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

(3)一個線程能夠包含多個協程。異步

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

(5)協程適合io密集型的程序,多線程適合計算密集型的程序(適用於多核cpu的狀況)。當你的程序大部分是文件讀寫操做或者網絡請求操做的時候,這時你應該首選協程而不是多線程,首先這些操做大部分不是利用cpu進行計算而是等待數據的讀寫,其次由於協程執行效率較高,子程序切換不是線程切換,是由程序自身控制,所以,沒有線程切換的開銷,和多線程比,線程數量越多,協程的性能優點就越明顯。 (6)使用協程能夠順序調用異步代碼,避免回調地獄。ide

2.簡單用法

這裏我打算模仿一個網絡請求,點擊button發送網絡請求,顯示一個progressbar打轉,返回結果後一個textview顯示結果並隱藏progressbar 先看一下佈局文件函數

<?xml version="1.0" encoding="utf-8"?>
<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"/>

</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,協程對初學者更易於學習。

4.最後

這年頭用Kotlin來開發android應用確實愈來愈爽快了,一些新的特性也逐漸加入到Kotlin中,值得更加學習,固然還有Flutter,之後會陸續寫幾個關於Flutter的文章,畢竟release了,我對它是十分看好的。

關注個人公衆號

相關文章
相關標籤/搜索