iT邦幫忙

2021 iThome 鐵人賽

DAY 30
1

有人說作為新手不好理解,我覺得蠻正常的,一來我中文其實不好,二來要理解新概念只用看的其實不夠,最好是動手寫code,將理解的概念自己用code呈現出來,這時概念就已經在腦中慢慢成形了; 另外我每篇必看的連結至少都看過3遍,也蠻建議搭配著看的

那對於我中文不好的部分,我會在未來有辦法講得更通順時回來改我的文章,或是你們可以留言你認為如何詮釋會更好

那要複習的其實很多,我這邊先下限制器,每篇能用的中文字只有60字,我會在裡面講完重點,只有範例的天數會直接跳過

大大大複習

在ide裡面,一個coroutine長這樣

CoroutineScope(Job())

你可以透過launch或是async去開始一個coroutineScope,launch是一種fire and forget的方式,並且她會回傳Job,async會回傳deferred,你要記得去await()蒐集他

在android裡面,還提供lifecycleScope和viewModelScope倆的跟著android生命週期的scope

當你在coroutine裡面再建立coroutine

CoroutineScope(Job() + Dispatcher.IO).launch{
    launch (Dispatcher.default){
    
    }
    async{
    
    }
}

coroutineContext就會被繼承,name、Dispatcher、ExceptionHandler是可以被繼承或是替換的,範例中的Dispatcher就被替換成default

而傳入的Job會被認定是新coroutine的parent,並且Job不會繼承,而是系統分配實例,你也可以透過獲得job去做細部處理,像是取消或等待

coroutine的父子關係很重要,因為它會深深影響exception和cancel,在這裡,cancel其實是透過丟出一個cancelException來做取消,而coroutine會判斷,如果是cancelException就不向上傳遞,而如果是其他的Exception會向上傳遞並取消sibling,直到root

但我們其實也有方法解決,透過SupervisorScope、supervisorJob(),或是ExceptionHandler可以防止全部的coroutine被一個exception取消任務

而coroutine本身也需要開發者對其做取消

val newScope = CoroutineScope(Job())
...
newScope.cancel()

經常和coroutine一起使用的有withContext和suspend,suspend透過編譯,可以做出感覺像掛起的功能,而withContext則可以讓你把block裡的任務切換dispatcher,等任務結束再切回來

那除了one shot的請求,coroutine同樣提供了資料流的方式flow

flow底下又有shareflow、stateflow、callbackflow,其實都有異曲同工之妙

從最基本的flow開始,他是一個冷數據流,分三個部分producer、intermediary、consumer,producer不在意最後的結果,他只負責提供資料,intermedairy不是必須,但你可以用它改變流的內容,consumer最重要,透過呼叫consumer你才能啟動流

(0..5).asFlow()//producer
        .map{//intermediary
            it * 2
        }
        .collect {//consumer
            Timber.d(it.toString())
        }


callbackFlow其實就是提供一個簡單的方法,讓你把callback變成flow

 callbackFlow<Post> {
     callbackGetData{
         trysend()
     }
     callbackfail{
         close()
     }
 }

stateflow和shareflow都是熱數據流,意即他們可以獨立存在,同時他們也能一個流對多個consumer(在這裡稱為subscriber訂閱者),stateflow能夠真正意義上取代liveData,用法也非常相似,而他其實是繼承自shareflow設計的,兩者的最大的差異在於

  1. shareflow可以設置buffer而stateflow不行
  2. stateflow不會更新和舊值相同的新值
  3. stateflow只會最後保留一個值,可以透過value去取

coroutine還有一個東西叫channel,簡單說他就是一個可以橫跨coroutine的queue

而實際開發上,其實還有併發問題,android應該比較容易遇到按鈕重複觸發,最簡單就是禁用按鈕直到result回來

而在server或是應用上有特殊需求也可以用其他解法

  1. 以最新的為主
  2. 取消新請求
  3. 一個一個執行

類似的情境還有大量操作,這時volatile沒用,result可以分成兩類解法,共享數據和消息傳遞

共享數據就以atomic和mutex代表,而消息傳遞以actor代表,至於將任務限制到單線程執行也是可以,但我不確定要分到哪

以上30天的基本coroutine就講完了:)

感言

那這系列為什麼要說是新手向呢?
我是希望給只會day2用法的新手看,讓你們看完可以踏出新手後的第一步(這步有點多就是了),更重要的是當你概念清楚了,不論是debug、寫測試、看別人的code,你可以很快進入狀況

在聊一下我自己寫完文章後的感想,其實沒有到很深吧,我已經盡量跳過source code和底層實現了,當然這些也很重要,請各位自己去看,因為我不想講哈哈哈哈哈

那這系列的文章,我覺得在深度上應該只涵蓋3~5%,考慮到達克曲線還可能更低,你說是不是該叫新手向

那講到測試,我在20天時其實就再考慮後面的進度怎麼排,flow後測試和併發應該只能選一個,好在今年不只我講coroutine,所以這邊我直接開門,測試看這裡,他也是今年鐵人賽寫coroutine的開發者,也可以去看看他的文章,學習還是要多了解,因為每個人其實都會有理解盲點

10/29 更 看到不錯的coroutine測試文章,kt academy test coroutine,應該會比上面的更多內容。

這個連結裡面有kt academy蠻多關於coroutine的文章,連結
這個連結裡面有android 官方coroutine文章,連結


上一篇
day29 大量操作怎麼辦? 連volatile都救不了我QQ
系列文
解鎖kotlin coroutine的各種姿勢-新手篇30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言