iT邦幫忙

2021 iThome 鐵人賽

DAY 15
0
Mobile Development

解鎖kotlin coroutine的各種姿勢-新手篇系列 第 15

day15 job的騷操作

今天再講些簡單的,順便複習複習前面的東西,之後又有幾天比較硬的內容
我們每次創建coroutine都匯回傳一個job,而我們除了cancel,還可以用他的其他方法

join

join會等待一個job結束

val scope = launch {
    delay(1000)
    Timber.d("scope")
    delay(1000)
    Timber.d("scope")
}

launch (Dispatchers.IO){
    Timber.d("io")
}
/**
 * io
 * scope
 * scope
 * */

那今天我改成這樣

val scope = launch {
    delay(1000)
    Timber.d("scope")
    delay(1000)
    Timber.d("scope")
}
scope.join()
launch (Dispatchers.IO){
    Timber.d("io")
}
/**
 * scope
 * scope
 * io
 * */

可以看到他會等待該scope任務結束在執行之後的程式

joinAll
既然已經了解了join,joinAll的概念也就呼之欲出了,等待複數個job工作結束

lifecycleScope.launch {

    val scope = launch {
        delay(1000)
        Timber.d("scope")
        delay(1000)
        Timber.d("scope")
    }
    val scope2 = launch {
        delay(1000)
        Timber.d("scope2")
        delay(1000)
        Timber.d("scope2")
    }
    joinAll(scope, scope2)
    launch (Dispatchers.IO){
        Timber.d("io")
    }
}

/**
 * scope
 * scope2
 * scope
 * scope2
 * io
 * */

find childs

fun checkJob() {
    val jjob = viewModelScope.launch {

        launch {
            delay(1000L)
            Timber.d("in launch $this")
        }
        launch {
            delay(1000L)
            Timber.d("in launch $this")
        }
    }
    jjob.children.forEach {
        Timber.d("find child $it")
    }
}

childeren可以找到該job的childrens,作為Sequence< Job>回傳,但無法找到child的child,另一方面,能找到的child,僅限以創建且還沒complete的job

以這個例子而言,如果把delay拿掉,launch作為fire and forget的coroutine,就不會被jjob.children.forEach印出

lazy start

val jjob = viewModelScope.launch (start = CoroutineStart.LAZY){

    launch {
        delay(1000L)
        Timber.d("in launch $this")
    }
    launch {
        delay(1000L)
        Timber.d("in launch $this")
    }
}
Timber.d("first log")
jjob.start()

開始coroutine這篇裡面,就有用到lazy start,不只是CoroutineScope可以用,以物件導向來理解的話,lifecycleScope和viewModelScope,可以當作繼承CoroutineScope的子類,所以用法沒甚麼區別,只有讓我們更方便而已

而start會遇到兩種情況,如果job還沒開始,就啟動coroutine,並返回true,否則返回false

isActive和ensureActive

val jjob = viewModelScope.launch {

    while (isActive){
        Timber.d("coffee")
    }
    while (true){
        ensureActive()
        Timber.d("milk")
    }
}
jjob.cancel()

兩個用途差不多,反正如果不檢查直接用while(true)會無法取消,詳情看取消

job.cancelAndJoin()
cancels the job and waits for its completion
我們在取消篇講過,job取消不是直接取消,是會先進入canceling state,那join是等待coroutine工作完成,cancelAndJoin,就是兩個一起用

//沒騙你,這是source code
public suspend fun Job.cancelAndJoin() {
    cancel()
    return join()
}

join和await比較

這樣看來,await和join都有等待的意思,但他們差異卻很大

launch回傳的job/ join,是一組用法,他們在遇到Exception的時候,會直接向上傳遞,並且他們是阻塞式的

async/await是另一組用法,遇到Exception的時候會將存放在Deferred< T>裡面,並期待開發者呼叫await,此外其非阻塞式的用法可以併發呼叫


上一篇
day14 channel實戰使用 with webSocket,後面離題講android接localhost
下一篇
day16 coroutine job 的那些狀態,job state
系列文
解鎖kotlin coroutine的各種姿勢-新手篇30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言