使用协程,相信很多同学已经信手拈来了,但是关于ViewModelScope,可能很多同学在用,但却不知道原理,今天来一探究竟。
ViewModelScope,顾名思义,在ViewModel中使用的协程。它是ViewModel的扩展属性。
推荐理由:
后面会重点介绍ViewModelScope是怎么做到不会内存泄漏的。
ViewModelScope虽然是协程,但属于androidx.lifecycle包中ViewModel的扩展属性。
使用非常简单,关键在于它是怎么保证不会内存泄露的?
来看viewModelScope源码:
先看get()方法:
return中通过setTagIfAbsent创建了协程,并且指定主线程。
先忽略setTagIfAbsent,来看协程创建的方式:
CloseableCoroutineScope,顾名思义,可以关闭的协程。
实现Closeable接口,并重写唯一方法close(),并在方法中取消了协程。
现在我们已经知道了viewModelScope是可以取消的了,关键就在于取消时机的控制了。
回过头在再看setTagIfAbsent,setTagIfAbsent是ViewModel中的方法
在setTagIfAbsent中,以HashMap的形式把协程对象保存起来了,并配有getTag方法。
可能有同学已经注意到最后的方法closeWithRuntimeException,因为这个方法中调用了Closeable接口的close()方法,而close()方法就是用来取消协程的。
而closeWithRuntimeException方法是谁调用的呢,主要是ViewModel中的clear()方法。
这里是循环保存协程的HashMap,然后调用closeWithRuntimeException取消协程。
那这个ViewModel中的clear()方法又是谁调用的呢?
查看源码,只有一处调用,就是在ViewModelStore中
ViewModelStore的源码比较少,也很简单。
同样也是以HashMap的形式来保存ViewModel。
那是什么时候保存的呢,我们来追踪一下put方法:
在ViewModelProvider的get方法中调用了put,也就是说,我们在创建ViewModel的时候并把其保存了起来。
回过头来再看ViewModelStore,同样也有一个clear()方法,同样循环调用vm.clear()。
继续追踪ViewModelStore的clear()方法是在哪调用的。
是在ComponentActivity.java中调用的:
先是获取Lifecycle,并添加生命周期监听。
在生命周期为onDestroy的时候,获取ViewModelStore,并调用其clear()方法。
至此,相信大部分同学都明白了ViewModelScope为什么不会造成内存泄露了,因为在onDestroy的时候会取消执行,只不过这部分工作源码已经替我们完成了。
关于怎么获取到当前生命周期状态的,就涉及到Lifecycle相关的知识了,简而言之,不管是Activity还是Fragment,都是LifecycleOwner,其实是父类实现的,比如ComponentActivity。在父类中通过ReportFragment或ActivityLifecycleCallbacks接口来派发当前生命周期状态,具体使用哪种派发方式要看Api等级是否在29(10.0)及以上,及 则后者。
author:yechaoa
最后,我们再来总结一下ViewModelScope的整个流程。
为避免有的同学没理解,我们再反推梳理一次
ok,以上就是ViewModelScope的使用,以及源码分析。
写作不易,如果对你有一丢丢帮助或启发,感谢点赞支持 ^ - ^
评论留言