網站首頁 編程語言 正文
先看一下?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) {//判斷是否已經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 內的 mBagOfTags 中
這個 mBagOfTags 是
private final Map<String, Object> mBagOfTags = new HashMap<>();
這個時候 我們 viewModel 就會持有 我們 viewModelScope 的協程 作用域了。那..這也只是 表述了 我們 viewModelScope 存在哪里而已,什么時候清除呢?
先看一下 ViewModel 的生命周期:
可以看到 ViewModel 的生命周期 會在 Activity onDestory 之后會被調用。那...具體哪里調的?
翻看源碼可以追溯到?ComponentActivity?的默認構造器內
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();
}
}
}
});
}
可以看到內部會通對 Lifecycle 添加一個觀察者,觀察當前 Activity 的生命周期變更事件,如果走到了 Destory ,并且 本次 Destory 并非由于配置變更引起的,才會真正調用 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 內部實現 用 HashMap 存儲 ViewModel
于是在 clear 的時候,會逐個遍歷調用 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();
}
可以發現我們最初 存放 viewmodelScope 的 mBagOfTags
這里面的邏輯 就是對 mBagOfTags 存儲的數據 挨個提取出來并且調用 closeWithRuntimeException
跟進 closeWithRuntimeException:
private static void closeWithRuntimeException(Object obj) {
if (obj instanceof Closeable) {
try {
((Closeable) obj).close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
該方法內會逐個判斷 對象是否實現 Closeable 如果實現就會調用這個接口的 close 方法,
再回到最初 我們 viewModel 的擴展方法那邊,看看我們 viewModelScope 的真正面目
internal class CloseableCoroutineScope(context: CoroutineContext)
: Closeable, CoroutineScope {
override val coroutineContext: CoroutineContext = context
override fun close() {
coroutineContext.cancel()
}
}
可以明確的看到 我們的 ViewModelScope 實現了 Closeable 并且充寫了 close 方法,
close 方法內的實現 會對 協程上下文進行 cancel。
至此我們 可以大致整理一下:
- viewModelScope 是 ViewModel 的擴展成員,該對象是 CloseableCoroutineScope,并且實現了 Closeable 接口
- ViewModelScope 存儲在 ViewModel 的 名叫?mBagOfTags?的HashMap中 啊
- ViewModel 存儲在 Activity 的 ViewModelStore 中,并且會監聽 Activity 的 Lifecycle 的狀態變更,在ON_DESTROY 且 非配置變更引起的事件中 對 viewModelStore 進行清空
- ViewModelStore 清空會對 ViewModelStore 內的所有 ViewModel 逐個調用 clear 方法。
- ViewModel的clear方法會對 ViewModel的 mBagOfTags 內存儲的對象進行調用 close 方法(該對象需實現Closeable 接口)
- 最終會會調用 我們 ViewModelScope 的實現類 CloseableCoroutineScope 的 close 方法中。close 方法會對協程進行 cancel。
原文鏈接:https://juejin.cn/post/7115406929165287438
相關推薦
- 2022-04-25 Entity?Framework?Core批處理SQL語句_實用技巧
- 2022-12-03 C++實現重載矩陣的部分運算符_C 語言
- 2022-06-16 golang?beego框架環境搭建過程_Golang
- 2022-06-01 C語言詳細分析常見字符串函數與模擬實現_C 語言
- 2022-08-29 Python如何利用pandas讀取csv數據并繪圖_python
- 2023-07-10 Spring事務的傳播機制
- 2022-03-14 JasperReport報表導出PDF中文不顯示的問題
- 2022-10-14 nginx 反向代理以及 location /admin/
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支