Kotlin協程快速入門

協程,全稱能夠譯做協同程序,不少語言都有這個概念和具體實現,以前入門Python的時候接觸過,而Kotlin其實也早就有這個擴展功能庫了,只不過以前一直處於實驗階段,不過前段時間1.0的正式版終於出了,網上的相關博客也多了起來,通過這幾天的學習我也來作下小結吧。android

環境配置

首先貼下Kotlin協程的官方github地址kotlinx.coroutines,下面的配置都是參照這裏的說明,並且裏面還貼心的給咱們準備了不少基礎的示例代碼,感興趣的的小夥伴稍後能夠去看看。git

首先配置下Kotlin版本github

buildscript {
    ext.kotlin_version = '1.3.11'
}
複製代碼

而後引入依賴,目前最新版是1.1.0bash

implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.1.0'
   implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.1.0'
複製代碼

配置很簡單,接下來幹什麼呢。固然是寫個協程版的Hello World了!閉包

import kotlinx.coroutines.*

fun main() {
    GlobalScope.launch { // 建立並啓動一個協程
        delay(1000L) // 延遲(掛起)1000毫秒,注意這不會阻塞線程
        println("World!") //延遲以後執行打印
    }
    println("Hello,") // 協程延遲的時候不會影響主線程的執行
    Thread.sleep(2000L) // 阻塞線程2s,保證JVM存活,協程可正常執行完
}
複製代碼

運行結果:ide

2018-12-23 17:35:16.998 15539-15539/com.renny.kotlin I/System.out: Hello,
2018-12-23 17:35:18.005 15539-18893/com.renny.kotlin I/System.out: World!
複製代碼

基礎語法

啓動模式

上面的協程啓動模式是默認的DEAFAULT,也就是建立並當即啓動的,咱們也能夠設置啓動模式爲LAZY,來本身安排是何時須要啓動:函數

fun main() {
        val job = GlobalScope.launch(start = CoroutineStart.LAZY) {
            println("World!")
        }
        println("Hello,")
        job.start()
        Thread.sleep(2000L)
    }
複製代碼

在我所採用的Kotlin 1.3版本中,還有ATOMICUNDISPATCHED兩個額外的模式,可是如今仍是實驗版,這裏很少介紹。結果如上。CoroutineScope.launch一共有三個參數,而後介紹其餘兩個:學習

  • context: CoroutineContext = EmptyCoroutineContext:協程上下文
  • block: suspend CoroutineScope.() -> Unit:閉包參數,定義協程內須要執行的操做。

返回值爲Job對象。gradle

Job類

經過上面的例子,咱們知道了一個重要的點launch函數是有返回值的,它是一個Job的接口類型,除了配合LAZY來本身啓動一個協程,下面介紹下其餘幾個重要方法:ui

  • job.cancel()取消一個協程
fun main() {
        val job = GlobalScope.launch {
            delay(1000L)
            println("World!")
        }
        job.cancel()
        println("Hello,")

    }
複製代碼

協程被取消了,因此只打印了Hello,

  • join()等待協程執行完畢
fun main() = runBlocking {
    val job = GlobalScope.launch {
        delay(1000L)
        println("World!")
        delay(1000L)
    }
    println("Hello,")
    job.join() 
    println("Good!")
}
複製代碼

做用很像Thread.join()函數,join()後面的代碼會等到協程結束再執行,結果以下:

2018-12-24 21:19:41.153 23484-23484/com.renny.kotlin I/System.out: Hello,
2018-12-24 21:19:42.148 23484-24172/com.renny.kotlin I/System.out: World!
2018-12-24 21:19:43.161 23484-23484/com.renny.kotlin I/System.out: Good!
複製代碼
  • job.cancelAndJoin()等待協程執行完畢而後再取消 這是一個 Job 的擴展函數,它結合了 canceljoin的調用,來看下它的實現:
public suspend fun Job.cancelAndJoin() {
    cancel()
    return join()
}
複製代碼

掛起函數

細心的同窗可能發現了兩個不通點,Job.join()函數被一個名字叫runBlocking的包圍了,而Job.start()Job.cancel都沒有;Job.cancelAndJoin()前面被一個特殊的關鍵詞suspend修飾了,這有什麼用呢?

其實經過查看源碼,Job.join()也被suspend修飾了,因此這是一個suspend(掛起)函數,掛起函數必須在協程中或者掛起函數中使用,由於調用了Job.join()Job.cancelAndJoin()也必須加上suspend聲明。事實上,要啓動協程,必須至少有一個掛起函數。

協程及協程掛起:

協程是經過編譯技術實現的,不須要虛擬機VM/操做系統OS的支持,經過相關代碼來生效

協程的掛起幾乎無代價,無需上下文切換或涉及OS

協程不能在隨機指令中掛起,只能在掛起點掛起(調用標記函數)!
複製代碼

子協程

上面咱們都是在線程中開啓一個協程,一樣在協程中咱們也能開啓另外一個協程,因此咱們再來看下複雜點的例子:

fun main() = runBlocking {
        GlobalScope.launch {
            delay(1000L)
            println("World!")
        }
        println("Hello,") 
        runBlocking {     
            delay(2000L)  
        }
    }
複製代碼

最外層的runBlocking爲最高級的協程 (通常爲主協程), 其餘協程如launch {} 由於層級較低能跑在runBlocking裏。runBlocking的最大特色就是它的delay()能夠阻塞當前的線程,和Thread.sleep()有着相同的效果。打印的日誌同第一個示例。

Job類中會存儲子協程的集合:

public val children: Sequence<Job>
複製代碼

一樣也提供了取消所有子協程的方法:

public fun Job.cancelChildren() {
    children.forEach { it.cancel() }
}
複製代碼

小結

這篇主要介紹了協程引入Android項目的配置,協程的一些基本操做,掛起函數的概念,你們對協程有一個基本的概念,下一篇將講下協程的更多知識。

參考文章

Kotlin協程官方文檔

相關文章
相關標籤/搜索