[协程]-[详解]-[协程作用域]-viewModelScope

概念

viewModelScope 跟 lifecycleScope 很像, 也会在特定时候自己取消自己, 确保不会出现内存泄漏

viewModelScope 是一个协程作用域, 是 ViewModel 的一个扩展属性, 在 ViewModel 销毁时会自己取消自己.


使用

Kotlin 复制代码
class MyViewModel : ViewModel() {
    fun loadData() {
        // 直接启动协程,无需担心 Activity 旋转或销毁导致的泄露
        viewModelScope.launch {
            val result = repository.getData() // 挂起函数
            _uiState.value = result
        }
    }
}

源码解析

ViewModel.viewModelScope

可以看到, viewModelScope 并未使用类似 LifecycleScope 的CAS自旋安全构建单例的方式, 而是直接通过加 synchronized 锁方式并发安全构建, 并最终挂载到对象Tag集合中.

上下文倒与LifecycleScope相同, 都使用了SupervisorJob + Dispatchers.Main.immediate

Kotlin 复制代码
public 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)
        )
    }

与 LifecycleScope 不一样的是, 它不依赖生命周期的监听. 而是专门写了 ViewModel 对象销毁机制. "ViewModel 在执行 clear() 时, 会自动遍历并回调 Scope 的 close() 方法",

具体代码如何, 让我们扒一扒 CloseableCoroutineScope...

CloseableCoroutineScope

CloseableCoroutineScope 代码很简单, 就是一个实现了Closeable接口的协程作用域(CoroutineScope), 他实现了close 方法, 并在方法中执行了cancel

Kotlin 复制代码
internal class CloseableCoroutineScope(
    context: CoroutineContext
) : Closeable, CoroutineScope {
    // 持有并暴露协程上下文
    override val coroutineContext: CoroutineContext = context

    /**
     * 当 ViewModel 销毁,触发 mBagOfTags 遍历时,
     * 会调用此 close() 方法。
     */
    override fun close() {
        coroutineContext.cancel()
    }
}

那 close 方法又是怎么保证被执行的呢?

原来, ViewModel 有自己的销毁机制, 在执行ViewModel.clear时, 会遍历一个叫做mBagOfTags的集合 (viewModelScope构建时, 就会将CloseableCoroutineScope构建后塞入这个集合), 如果类型是Closeable的, 就会执行Closeable.close()

具体ViewModel.clear代码如下

Kotlin 复制代码
/** ViewModel.kt */
@MainThread
final void clear() {
    mCleared = true;
    
    // viewModelScope 在构建时, 会把CloseableCoroutineScope构建后
    // 塞到ViewModel.mBagOfTags中, 在执行ViewModel.clear时会遍历这个mBagOfTags
    // 如果发现 item 是 Closeable 类型, 就执行close
    synchronized (mBagOfTags) {
        for (Object value : mBagOfTags.values()) {
            // 2. 关键:在这里执行 closeNext()
            closeWithRuntimeException(value);
        }
    }
    onCleared(); // 开发者重写的那个方法
}

/** ViewModel.java */
private static void closeWithRuntimeException(Object obj) {
    if (obj instanceof Closeable) {
        try {
            ((Closeable) obj).close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

自此 viewModelScope 从如何构建到如何自动取消的流程, 都基于源码解析完了, 接下来我们做个总结


总结

viewModelScope 是 ViewModel 的扩展属性, 实际上是 CloseableCoroutineScope 类对象, CloseableCoroutineScope 组合了 Closeable 和 CoroutineScope 的能力

在ViewModel中使用viewModelScope时, 系统会结合 synchronized锁 并发安全地构建CloseableCoroutineScope 对象, 并存入ViewModel中一个名为 mBagOfTags 的 Map集合中, 在最终执行 ViewModel.clear() 时会遍历这个Map, 当item为Closeable类型时, 执行close, 然后内部直接cancel掉这个协程作用域.

这样一来, 就实现了viewModelScope 的自动取消能力了.

相关推荐
新缸中之脑2 小时前
使用 AI 进行科学调试
android·人工智能·kotlin
QING6183 小时前
Android Gradle Plugin 9.0 升级指南:告别十年技术债,你准备好了吗?
android·kotlin·gradle
Kapaseker4 小时前
一杯美式理解 Inner Class
android·kotlin
su1ka11118 小时前
kotlin(1)介绍
kotlin·intellij-idea
147API1 天前
Claude JSON 稳定输出:Schema 校验与修复回路(Kotlin)
开发语言·kotlin·json·claude
Kapaseker1 天前
解析 Compose 的核心概念 remember
android·kotlin
秋知叶i1 天前
【Android Studio】Kotlin 第一个 App Hello World 创建与运行|超详细入门
android·kotlin·android studio
榴月子1 天前
Mac 安装 Homebrew、 Java 和 Kotlin
java·macos·kotlin
ysh98881 天前
2025年 Android Studio修仙传(kotlin版):基础篇
android·kotlin·android studio