iT邦幫忙

2021 iThome 鐵人賽

DAY 26
0
Mobile Development

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

day26 老闆我趕時間,給我最快完成的料理 select

提醒,select仍是實驗中的api,請斟酌使用

在這之前的26天,我們所用的都是我要做什麼事,就是做什麼事,不會有條件的選取,但作為android的開發者,一定聽過google爸爸說過single trust of source,在架構的最佳化那篇裡面,他以最近是否活躍為判斷連結

那我這邊再多舉一個例子,假如你的應用可以離線存取,同時也有客製排序的功能,用戶對這項功能的調整頻率較低,你可能會選擇遠端一份排序邏輯資料,本地一份排序邏輯資料

如果是用戶自己設置,你可以在設置確認後先發到遠端,在更新本地,如果是slope one的算法你可以考慮用workManager去定時fetch等等,在多種情境下我們會做不同的考量,而我這裡在系列文裡最後介紹一個coroutine的工具,select

中文好像叫多路復用,其實他就是會先拿到最早available的值

viewModelScope.launch {
    val orderRule = select<OrderResponse<OrderRule>> {
        async { localOrder() }.onAwait{ OrderResponse(it, isLocal = true)}
        async { remoteOrder() }.onAwait{ OrderResponse(it, isLocal = false) }
    }
}

channel

不知道channel的人轉這裡

而select也可以接收多個channel,通常我們一個channel是可以由多個priducer和多consumer對吧

但如果需求是要同時接收不同的channel呢? 最適合的工具就是select了

suspend fun selectFizzBuzz(fizz: ReceiveChannel<String>, buzz: ReceiveChannel<String>) {
    select<Unit> { // <Unit> 意味着该 select 表达式不返回任何结果
        fizz.onReceive { value ->  // 这是第一个 select 子句
            println("fizz -> '$value'")
        }
        buzz.onReceive { value ->  // 这是第二个 select 子句
            println("buzz -> '$value'")
        }
    }
}
val fizz = fizz()//啟動一個corotine,每0.3秒丟值
val buzz = buzz()//啟動一個corotine,每0.5秒丟值
repeat(7) {
    selectFizzBuzz(fizz, buzz)
}//蒐集7個
coroutineContext.cancelChildren() //取消兩個coroutine

文檔給的範例非常簡單,我也就不多加敘述了

那如果蒐集到已經close的channel要怎麼半?

onReceive會throw Exception,但我們可以用onReceiveOrNull,如果channel close他會回傳null,而我們可以再對此作處理

b.onReceiveOrNull { value -> 
    if (value == null) 
        "Channel 'b' is closed"
    else    
        "b -> '$value'"
}

而channel的接收和發送都會suspend,select也能對發送做出處理

fun CoroutineScope.produceNumbers(side: SendChannel<Int>) = produce<Int> {
    for (num in 1..10) { // 生产从 1 到 10 的 10 个数值
        delay(100) // 延迟 100 毫秒
        select<Unit> {
            onSend(num) {} // 发送到主通道
            side.onSend(num) {} // 或者发送到 side 通道
        }
    }
}

大概醬,因為再channel的consume那邊,可能會執行其他動作,這時select救苦以盡快將值發給已經可以此用的channel裡面

其實select是個比較少用到的功能,但聽我講講你也不吃虧,先有個概念,未來遇到問題時也能很快聯想到這個解法,今天就這樣,掰掰

連結

必看

文檔

選看

別人講的
別人講的


上一篇
day25 矮額是callback,把它變成flow好了 簡單的callbackFlow
下一篇
day27 coroutine和任務的愛情長跑,application和workManager
系列文
解鎖kotlin coroutine的各種姿勢-新手篇30

尚未有邦友留言

立即登入留言