Coroutine 學(xué)習(xí)(二)ViewModelScope LifeCycleScope Dispatcher
問題:
koin如何創(chuàng)建ViewModel?
ViewModelScope和LifeCycleScope的最佳使用方式是什么?
ViewModel和Repository使用方式是什么 各自的職責(zé)是什么?
Room和ViewModel應(yīng)該如何配合使用
單獨(dú)使用supsend函數(shù),suspend函數(shù)表示的協(xié)程和它所在的CoroutineScope的生命周期相同嗎?
我們所使用的Dispatchers.Main IO 是一個【單例】嗎?

Koin
首先需要明確module, Service, scope這些概念和我們之前所了解的都不同,在談及Koin的上下文時,這些都是Koin定義的概念
Koin使用步驟
Koin是一種實(shí)現(xiàn)依賴注入的方式,使用的時候需要遵循的步驟
定義KoinModule
????2. 在application中注冊:
Service的創(chuàng)建:
factory single viewModel都可以創(chuàng)建Service到Module中

生命周期
Service的創(chuàng)建方式還指定了Service的生命周期??梢宰远xScope的生命周期
依賴注入方式:
1. get
定義在module中的類需要參數(shù),可以通過get聲明參數(shù)。Koin會在module中尋找是否存在對應(yīng)的Service
在其他地方也可以通過get方法獲取實(shí)例:
2. 懶加載inject

在Android中使用協(xié)程的最佳做法:
https://developer.android.google.cn/kotlin/coroutines/coroutines-best-practices?hl=zh-cn

在Android ViewModel中使用協(xié)程的最佳方式
在ViewModel中使用協(xié)程的一個方式是使用viewModelScope,因?yàn)樽裱?strong>結(jié)構(gòu)化并發(fā)思想。
結(jié)構(gòu)化并發(fā):
內(nèi)容:使得每一個協(xié)程都運(yùn)行在指定的CoroutineScope中
為什么要這么做:
是我們的每一個suspend、協(xié)程都不會產(chǎn)生lost or leak
保證所有的異常都能夠正確的處理
對于lost和leak的理解:
因?yàn)樗械膮f(xié)程的生命都在一個上下文中,所以只要管理好上文的Scope,內(nèi)部的協(xié)程也可以被管理,當(dāng)關(guān)閉父協(xié)程(外面的scope)時,內(nèi)部的子協(xié)程也會被關(guān)閉。
ViewModel的生命周期

ViewModel的生命周期和創(chuàng)建它時傳入的LifeCycle組件的生命周期有關(guān)。使用viewScope我們能在viewScope中開啟協(xié)程也不用擔(dān)心內(nèi)存泄漏:
viewModelScope = SupervisorJob + Dispatchers.Main.immediate
當(dāng)ViewModel生命周期走到盡頭時,會調(diào)用clear方法其中又會調(diào)用closeWithRuntimeException。因?yàn)関iewModelScope又是一個CloseCoroutineScope,所以可以使用closeWithRuntimeException方法關(guān)閉。Dispatchers.Main.immediate判斷如果當(dāng)前在主線程,立馬執(zhí)行協(xié)程,不會通過Dispatcher再分發(fā)。

對于ViewModel職責(zé)的理解
ViewModel應(yīng)該是連接View和Model的橋梁。所以viewModelscope是在Main調(diào)度器上運(yùn)行。
如果在ViewModelScope中出現(xiàn)了異常,應(yīng)該選擇就地捕獲異常
src:https://developer.android.google.cn/kotlin/coroutines/coroutines-best-practices?hl=zh-cn

在協(xié)程中使用viewModelScope的方式?
https://medium.com/androiddevelopers/easy-coroutines-in-android-viewmodelscope-25bffb605471

Dipatcher:
協(xié)程中的Dispatchers.main Dispatchers.IO Dispatchers.default 這些會創(chuàng)建單例,還是每次調(diào)用都創(chuàng)建不同的實(shí)例?
Dispatchers.Main:

以上是Dispacthers.Main的構(gòu)建過程。Dispatcher.Main在文檔中的描述的特點(diǎn)是:該協(xié)程調(diào)度器被限定在了主線程中,可以和UI對象進(jìn)行交互。
MainDispatcherLoader
MainDispatcherLoader類是一個object,也就是說這個類是一個天生的單例。MainDispatcherLoader通過loadMainDispatcher創(chuàng)建了dispatcher。
接下來調(diào)用了MainDispatcherFactory的方法創(chuàng)建Dispacther
。MainDispatcherFactory的實(shí)現(xiàn)類只有AndroidDispatcherFactory一個。在AndroidDispatcherFatctory的重寫方法中,我們發(fā)現(xiàn)真正的返回對象是HandlerContext:

HandlerContext其中一個參數(shù)就是通過主線程的Looper構(gòu)建的Handler實(shí)例。所以其實(shí)現(xiàn)在已經(jīng)可以得出結(jié)論,每次調(diào)用Dispatchers.Main都會創(chuàng)建一個新的HandlerContext對象。我們通過這個Handler對象和主線程進(jìn)行交互。特別是可以看看這里的dispatch方法:
其他的Dispatcher也是類似的,所以我們可以在Koin Module中使用factory模塊生成Dispatcher的Service。
總結(jié):
理解協(xié)程首先需要理解什么叫做結(jié)構(gòu)性并發(fā)。結(jié)構(gòu)性并發(fā)保證了所有的協(xié)程、掛起函數(shù)都能被CoroutineScope管理生命周期。
創(chuàng)建一個協(xié)程會繼承CoroutineScope中的內(nèi)容,但是如果指定了Dispatchers.Main或者其他的Dispatchers.IO 這里不存在【單例】或者是【復(fù)用】機(jī)制,會重新創(chuàng)建一個Dispacthers的實(shí)例。