ViewModelScope 简介与使用

简介

  • 当在ViewModel中引入协程,如果直接使用CoroutineScope,那么需要在onCleared()方法中取消协程,如果忘记取消协程那么会导致出现内存泄漏等各种问题,此时需要使用ViewModel扩展属性viewModelScope来实现协程作用域。

viewModelScope源码分析

val ViewModel.viewModelScope: CoroutineScope
        get() {
            val scope: CoroutineScope? = this.getTag(JOB_KEY)
            if (scope != null) {
                return scope
            }
            // 默认使用Dispatchers.Main,方便Activity和Fragment更新UI
            return setTagIfAbsent(JOB_KEY,
                CloseableCoroutineScope(SupervisorJob() + Dispatchers.Main.immediate))
        }

// 为了ViewModel能够取消协程,需要实现Closeable接口
internal class CloseableCoroutineScope(context: CoroutineContext) : Closeable, CoroutineScope {
    override val coroutineContext: CoroutineContext = context


    override fun close() {
        coroutineContext.cancel()
    }
}

ViewModel如何创建以及取消CorutineScope

abstract class ViewModel
    // ViewModel通过HashMap存储CoroutineScope对象
    private final Map<String, Object> mBagOfTags = new HashMap<>();

    // ViewModel被销毁时内部执行clear()方法,
    @MainThread
    final void clear() {
        mCleared = true;
        if (mBagOfTags != null) {
            synchronized (mBagOfTags) {
                for (Object value : mBagOfTags.values()) {
                    // 取消viewModelScope作用域的协程
                    closeWithRuntimeException(value);
                }
            }
        }
        onCleared();
    }

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


    // 如果JOB_KEY已存在且对应的协程作用域不为空则返回对象,否则创建新的协程作用域,并设置JOB_KEY
    @SuppressWarnings("unchecked")
    <T> T setTagIfAbsent(String key, T newValue) {
        T previous;
        synchronized (mBagOfTags) {
            previous = (T) mBagOfTags.get(key);
            if (previous == null) {
                mBagOfTags.put(key, newValue);
            }
        }
        T result = previous == null ? newValue : previous;
        if (mCleared) {
            closeWithRuntimeException(result);
        }
        return result;
    }

    // 通过JOB_KEY从HashMap中返回相应的协程作用域
    @SuppressWarnings({"TypeParameterUnusedInFormals", "unchecked"})
    <T> T getTag(String key) {
        synchronized (mBagOfTags) {
            return (T) mBagOfTags.get(key);
        }
    }

}
©️2020 CSDN 皮肤主题: 技术黑板 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值