一文了解Android?ViewModelScope?如何自動(dòng)取消協(xié)程
先看一下 ViewModel 中的 ViewModelScope 是何方神圣
val ViewModel.viewModelScope: CoroutineScope get() { val scope: CoroutineScope? = this.getTag(JOB_KEY) if (scope != null) { return scope } return setTagIfAbsent(JOB_KEY, CloseableCoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)) }
可以看到這個(gè)是一個(gè)擴(kuò)展方法,
再點(diǎn)擊 setTagIfAbsent 方法進(jìn)去
<T> T setTagIfAbsent(String key, T newValue) { T previous; synchronized (mBagOfTags) { previous = (T) mBagOfTags.get(key);//第一次肯定為null if (previous == null) { mBagOfTags.put(key, newValue);//null 存儲(chǔ) } } T result = previous == null ? newValue : previous; if (mCleared) {//判斷是否已經(jīng)clear了 // It is possible that we'll call close() multiple times on the same object, but // Closeable interface requires close method to be idempotent: // "if the stream is already closed then invoking this method has no effect." (c) closeWithRuntimeException(result); } return result; }
可以看到 這邊 會(huì)把 我們的 ViewModel 存儲(chǔ)到 ViewModel 內(nèi)的 mBagOfTags 中
這個(gè) mBagOfTags 是
private final Map<String, Object> mBagOfTags = new HashMap<>();
這個(gè)時(shí)候 我們 viewModel 就會(huì)持有 我們 viewModelScope 的協(xié)程 作用域了。那..這也只是 表述了 我們 viewModelScope 存在哪里而已,什么時(shí)候清除呢?
先看一下 ViewModel 的生命周期:
可以看到 ViewModel 的生命周期 會(huì)在 Activity onDestory 之后會(huì)被調(diào)用。那...具體哪里調(diào)的?
翻看源碼可以追溯到 ComponentActivity 的默認(rèn)構(gòu)造器內(nèi)
public ComponentActivity() { /*省略一些*/ getLifecycle().addObserver(new LifecycleEventObserver() { @Override public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) { if (event == Lifecycle.Event.ON_DESTROY) { if (!isChangingConfigurations()) { getViewModelStore().clear(); } } } }); }
可以看到內(nèi)部會(huì)通對(duì) Lifecycle 添加一個(gè)觀察者,觀察當(dāng)前 Activity 的生命周期變更事件,如果走到了 Destory ,并且 本次 Destory 并非由于配置變更引起的,才會(huì)真正調(diào)用 ViewModelStore 的 clear 方法。
跟進(jìn) clear 方法看看:
public class ViewModelStore { private final HashMap<String, ViewModel> mMap = new HashMap<>(); /** * Clears internal storage and notifies ViewModels that they are no longer used. */ public final void clear() { for (ViewModel vm : mMap.values()) { vm.clear(); } mMap.clear(); } }
可以看到這個(gè) ViewModelStore 內(nèi)部實(shí)現(xiàn) 用 HashMap 存儲(chǔ) ViewModel
于是在 clear 的時(shí)候,會(huì)逐個(gè)遍歷調(diào)用 clear方法,再次跟進(jìn) ViewModel 的 clear 方法
@MainThread final void clear() { mCleared = true; // Since clear() is final, this method is still called on mock objects // and in those cases, mBagOfTags is null. It'll always be empty though // because setTagIfAbsent and getTag are not final so we can skip // clearing it if (mBagOfTags != null) { synchronized (mBagOfTags) { for (Object value : mBagOfTags.values()) { // see comment for the similar call in setTagIfAbsent closeWithRuntimeException(value); } } } onCleared(); }
可以發(fā)現(xiàn)我們最初 存放 viewmodelScope 的 mBagOfTags
這里面的邏輯 就是對(duì) mBagOfTags 存儲(chǔ)的數(shù)據(jù) 挨個(gè)提取出來并且調(diào)用 closeWithRuntimeException
跟進(jìn) closeWithRuntimeException:
private static void closeWithRuntimeException(Object obj) { if (obj instanceof Closeable) { try { ((Closeable) obj).close(); } catch (IOException e) { throw new RuntimeException(e); } } }
該方法內(nèi)會(huì)逐個(gè)判斷 對(duì)象是否實(shí)現(xiàn) Closeable 如果實(shí)現(xiàn)就會(huì)調(diào)用這個(gè)接口的 close 方法,
再回到最初 我們 viewModel 的擴(kuò)展方法那邊,看看我們 viewModelScope 的真正面目
internal class CloseableCoroutineScope(context: CoroutineContext) : Closeable, CoroutineScope { override val coroutineContext: CoroutineContext = context override fun close() { coroutineContext.cancel() } }
可以明確的看到 我們的 ViewModelScope 實(shí)現(xiàn)了 Closeable 并且充寫了 close 方法,
close 方法內(nèi)的實(shí)現(xiàn) 會(huì)對(duì) 協(xié)程上下文進(jìn)行 cancel。
至此我們 可以大致整理一下:
- viewModelScope 是 ViewModel 的擴(kuò)展成員,該對(duì)象是 CloseableCoroutineScope,并且實(shí)現(xiàn)了 Closeable 接口
- ViewModelScope 存儲(chǔ)在 ViewModel 的 名叫 mBagOfTags 的HashMap中 啊
- ViewModel 存儲(chǔ)在 Activity 的 ViewModelStore 中,并且會(huì)監(jiān)聽 Activity 的 Lifecycle 的狀態(tài)變更,在ON_DESTROY 且 非配置變更引起的事件中 對(duì) viewModelStore 進(jìn)行清空
- ViewModelStore 清空會(huì)對(duì) ViewModelStore 內(nèi)的所有 ViewModel 逐個(gè)調(diào)用 clear 方法。
- ViewModel的clear方法會(huì)對(duì) ViewModel的 mBagOfTags 內(nèi)存儲(chǔ)的對(duì)象進(jìn)行調(diào)用 close 方法(該對(duì)象需實(shí)現(xiàn)Closeable 接口)
- 最終會(huì)會(huì)調(diào)用 我們 ViewModelScope 的實(shí)現(xiàn)類 CloseableCoroutineScope 的 close 方法中。close 方法會(huì)對(duì)協(xié)程進(jìn)行 cancel。
到此這篇關(guān)于一文了解Android ViewModelScope 如何自動(dòng)取消協(xié)程的文章就介紹到這了,更多相關(guān)Android ViewModel Scope 取消協(xié)程內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android編程連接MongoDB及增刪改查等基本操作示例
這篇文章主要介紹了Android編程連接MongoDB及增刪改查等基本操作,簡(jiǎn)單介紹了MongoDB功能、概念、使用方法及Android操作MongoDB數(shù)據(jù)庫(kù)的基本技巧,需要的朋友可以參考下2017-07-07Android webview加載https鏈接錯(cuò)誤或無響應(yīng)的解決
這篇文章主要介紹了Android webview加載https鏈接錯(cuò)誤或無響應(yīng)的解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-03-03Android實(shí)現(xiàn)網(wǎng)易嚴(yán)選標(biāo)簽欄滑動(dòng)效果
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)網(wǎng)易嚴(yán)選標(biāo)簽欄滑動(dòng)效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-07-07Android開發(fā)獲取短信的內(nèi)容并截取短信
本文給大家介紹android開發(fā)獲取短信內(nèi)容并截取短息的相關(guān)內(nèi)容,本文代碼簡(jiǎn)單易懂,感興趣的朋友一起學(xué)習(xí)吧2015-12-12Android UI設(shè)計(jì)與開發(fā)之仿人人網(wǎng)V5.9.2最新版引導(dǎo)界面
這篇文章主要為大家詳細(xì)介紹了Android UI設(shè)計(jì)與開發(fā)之仿人人網(wǎng)V5.9.2最新版引導(dǎo)界面,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-08-08RxJava+Retrofit實(shí)現(xiàn)網(wǎng)絡(luò)請(qǐng)求封裝的方法
Retrofit是當(dāng)前應(yīng)用非常廣泛的網(wǎng)絡(luò)請(qǐng)求框架,通常結(jié)合RxJava來進(jìn)行網(wǎng)絡(luò)請(qǐng)求,本文將展示一個(gè)采用RxJava+Retrofit的網(wǎng)絡(luò)請(qǐng)求demo,感興趣的可以了解一下2019-04-04Android使用http實(shí)現(xiàn)注冊(cè)登錄功能
這篇文章主要為大家詳細(xì)介紹了Android使用http實(shí)現(xiàn)注冊(cè)登錄功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-04-04