当前位置:首页 > 谈天说地

一文了解Android ViewModelScope 如何自动取消协程

34资源网2022-07-04425

先看一下 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。

到此这篇关于一文了解android viewmodelscope 如何自动取消协程的文章就介绍到这了,更多相关android viewmodel scope 取消协程内容请搜索萬仟网以前的文章或继续浏览下面的相关文章希望大家以后多多支持萬仟网!

看完文章,还可以扫描下面的二维码下载快手极速版领4元红包

快手极速版二维码

快手极速版新人见面礼

除了扫码领红包之外,大家还可以在快手极速版做签到,看视频,做任务,参与抽奖,邀请好友赚钱)。

邀请两个好友奖最高196元,如下图所示:

快手极速版邀请好友奖励

扫描二维码推送至手机访问。

版权声明:本文由34楼发布,如需转载请注明出处。

本文链接:https://www.34l.com/post/18454.html

分享给朋友:

相关文章

情浓时,海誓山盟;情淡时,形同陌路

情浓时,海誓山盟;情淡时,形同陌路

1、如果一个人影响到了你的情绪,你的焦点应该放在控制自己的情绪上,而不是影响你情绪的人身上。只有这样,才能真正自信起来。…

闪客快跑2背景音乐(闪客快打andylaw的微博)

闪客快跑2背景音乐(闪客快打andylaw的微博)

《疯狂跑酷》是一款LowPoly(低多边形)画风的跑酷游戏,一场突如其来的大水淹没了城市,而你在游戏中扮演一名刚下班的男子,需要从被水淹没的城市中逃出生天。…

一周涨粉几百万,“张同学”凭什么火?

一周涨粉几百万,“张同学”凭什么火?

编者按:本文来自微信公众号时趣研究院(ID:SocialTouch2020),作者:时有趣,创业邦经授权转载 在最近的一段时间里,名叫“张同学”的博主刷屏了抖音,相关话题频频登上热榜,甚至还得到了人民网的点评。 张同学第一个视频的发布日期…

飞行汽车是一种应用层创新

飞行汽车是一种应用层创新

编者按:本文来自A轮财经,创业邦经授权发布。 作者|WX 今天在全球范围内,飞行汽车得到了越来越多的关注。 据摩根士丹利研报预计,2030年飞行汽车行业将形成3000亿美元的市场规模。2040年,该行业规模可能将达到1.5万亿美元。 作为新…

刘强东章泽天携手布局,“大厂”为何掀起私募热潮?

刘强东章泽天携手布局,“大厂”为何掀起私募热潮?

编者按:本文来自雷达财经(ID:leidacj),创业邦经授权发布。 作者|张凯旌 编辑|深海 京东在私募股权投资上又有新动作。 11月29日,由刘强东、章泽天、李瑞玉共同持股的海南三亚天博产业私募基金管理有限公司(下称“海南天博私…

win7开始菜单设置在哪里(win7开始菜单变成经典模式)

win7开始菜单设置在哪里(win7开始菜单变成经典模式)

我们在用win7系统的时候,发现打开了一些程序后,会在开始菜单那里显示这些最近打开的程序。有些人不想把自己最近打开的程序显示在这里,那么怎么可以删除这些程序,或者彻底让这里不会显示最近打开程序呢?下面我来教大家删除或设置不显示最近打开的程序…