一文了解Android?ViewModelScope?如何自動取消協(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))
}可以看到這個是一個擴展方法,
再點擊 setTagIfAbsent 方法進去
<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 存儲
}
}
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;
}可以看到 這邊 會把 我們的 ViewModel 存儲到 ViewModel 內(nèi)的 mBagOfTags 中
這個 mBagOfTags 是
private final Map<String, Object> mBagOfTags = new HashMap<>();
這個時候 我們 viewModel 就會持有 我們 viewModelScope 的協(xié)程 作用域了。那..這也只是 表述了 我們 viewModelScope 存在哪里而已,什么時候清除呢?
先看一下 ViewModel 的生命周期:

可以看到 ViewModel 的生命周期 會在 Activity onDestory 之后會被調(diào)用。那...具體哪里調(diào)的?
翻看源碼可以追溯到 ComponentActivity 的默認構(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)部會通對 Lifecycle 添加一個觀察者,觀察當前 Activity 的生命周期變更事件,如果走到了 Destory ,并且 本次 Destory 并非由于配置變更引起的,才會真正調(diào)用 ViewModelStore 的 clear 方法。
跟進 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();
}
}可以看到這個 ViewModelStore 內(nèi)部實現(xiàn) 用 HashMap 存儲 ViewModel
于是在 clear 的時候,會逐個遍歷調(diào)用 clear方法,再次跟進 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
這里面的邏輯 就是對 mBagOfTags 存儲的數(shù)據(jù) 挨個提取出來并且調(diào)用 closeWithRuntimeException
跟進 closeWithRuntimeException:
private static void closeWithRuntimeException(Object obj) {
if (obj instanceof Closeable) {
try {
((Closeable) obj).close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}該方法內(nèi)會逐個判斷 對象是否實現(xiàn) Closeable 如果實現(xiàn)就會調(diào)用這個接口的 close 方法,
再回到最初 我們 viewModel 的擴展方法那邊,看看我們 viewModelScope 的真正面目
internal class CloseableCoroutineScope(context: CoroutineContext)
: Closeable, CoroutineScope {
override val coroutineContext: CoroutineContext = context
override fun close() {
coroutineContext.cancel()
}
}可以明確的看到 我們的 ViewModelScope 實現(xiàn)了 Closeable 并且充寫了 close 方法,
close 方法內(nèi)的實現(xiàn) 會對 協(xié)程上下文進行 cancel。
至此我們 可以大致整理一下:
- viewModelScope 是 ViewModel 的擴展成員,該對象是 CloseableCoroutineScope,并且實現(xiàn)了 Closeable 接口
- ViewModelScope 存儲在 ViewModel 的 名叫 mBagOfTags 的HashMap中 啊
- ViewModel 存儲在 Activity 的 ViewModelStore 中,并且會監(jiān)聽 Activity 的 Lifecycle 的狀態(tài)變更,在ON_DESTROY 且 非配置變更引起的事件中 對 viewModelStore 進行清空
- ViewModelStore 清空會對 ViewModelStore 內(nèi)的所有 ViewModel 逐個調(diào)用 clear 方法。
- ViewModel的clear方法會對 ViewModel的 mBagOfTags 內(nèi)存儲的對象進行調(diào)用 close 方法(該對象需實現(xiàn)Closeable 接口)
- 最終會會調(diào)用 我們 ViewModelScope 的實現(xiàn)類 CloseableCoroutineScope 的 close 方法中。close 方法會對協(xié)程進行 cancel。
到此這篇關(guān)于一文了解Android ViewModelScope 如何自動取消協(xié)程的文章就介紹到這了,更多相關(guān)Android ViewModel Scope 取消協(xié)程內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android中不支持動態(tài)申請權(quán)限的原因
這篇文章主要介紹了Android中不支持動態(tài)申請權(quán)限的原因,本文列舉了幾個不支持動態(tài)申請權(quán)限的原因,需要的朋友可以參考下2015-01-01
android使用DataBinding來設(shè)置空狀態(tài)
本篇文章主要介紹了android使用DataBinding來設(shè)置空狀態(tài),具有一定的參考價值,感興趣的小伙伴們可以參考一下。2017-03-03
Android 中WebView 截圖的實現(xiàn)方式
這篇文章主要介紹了Android 中WebView 截圖的實現(xiàn)方式,WebView 作為一種特殊的控件,自然不能像其他系統(tǒng) View 或者截屏的方式來獲取截圖。本文通過實例代碼給大家介紹的非常詳細,需要的朋友參考下吧2017-12-12
Android Service判斷設(shè)備聯(lián)網(wǎng)狀態(tài)詳解
本文主要介紹Android Service判斷聯(lián)網(wǎng)狀態(tài),這里提供了相關(guān)資料并附有示例代碼,有興趣的小伙伴可以參考下,幫助開發(fā)相關(guān)應(yīng)用功能2016-08-08
Android開發(fā)案例手冊Application跳出dialog
這篇文章主要為大家介紹了Android開發(fā)案例手冊Application跳出dialog,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-06-06
android不同activity之間共享數(shù)據(jù)解決方法
最近做局域網(wǎng)socket連接問題,要在多個activity之間公用一個socket連接,就在網(wǎng)上搜了下資料,感覺還是application方法好用,帖出來需要的朋友可以參考下2012-11-11

