if (!isChangingConfigurations()) {

getViewModelStore().clear();

}

}

}

});

}

在Activity的生命周期走到onDestroy的时候调用ViewModelStore的clear做收尾工作。但是,注意一下,这个调用有个前提,此次走onDestroy不是因为配置更改才会去调用clear方法。

好的,到此为止,咱们理通了viewModelScope的协程是怎么做到自动取消的(ViewModel的mBagOfTags),以及是在什么时候进行取消的(ViewModel的clear()时)。

3. lifecycleScope

对于Lifecycle,Google贴心地提供了LifecycleScope,我们可以直接通过launch来创建Coroutine。

3.1 使用

举个简单例子,比如在Activity的onCreate里面,每隔100毫秒更新一下TextView的文字。

lifecycleScope.launch {

repeat(100000) {

delay(100)

tvText.text = “$it”

}

}

因为LifeCycle是可以感知组件的生命周期的,所以Activity一旦onDestroy了,相应的上面这个lifecycleScope。launch闭包的调用也会取消。

另外,lifecycleScope还贴心地提供了launchWhenCreated、launchWhenStarted、launchWhenResumed方法,这些方法的闭包里面有协程的作用域,它们分别是在CREATED、STARTED、RESUMED时被执行。

//方式1

lifecycleScope.launchWhenStarted {

repeat(100000) {

delay(100)

tvText.text = “$it”

}

}

//方式2

lifecycleScope.launch {

whenStarted {

repeat(100000) {

delay(100)

tvText.text = “$it”

}

}

}

不管是直接调用launchWhenStarted还是在launch中调用whenStarted都能达到同样的效果。

3.2 LifecycleScope的底层实现

先来看下lifecycleScope.launch是怎么做到的

/**

  • [CoroutineScope] tied to this [LifecycleOwner]'s [Lifecycle].

  • This scope will be cancelled when the [Lifecycle] is destroyed.

  • This scope is bound to

  • [Dispatchers.Main.immediate][kotlinx.coroutines.MainCoroutineDispatcher.immediate].

*/

val LifecycleOwner.lifecycleScope: LifecycleCoroutineScope

get() = lifecycle.coroutineScope

好家伙,又是扩展属性。这次扩展的是LifecycleOwner,返回了一个LifecycleCoroutineScope。每次在get的时候,是返回的lifecycle.coroutineScope,看看这个是啥。

/**

  • [CoroutineScope] tied to this [Lifecycle].

  • This scope will be cancelled when the [Lifecycle] is destroyed.

  • This scope is bound to

  • [Dispatchers.Main.immediate][kotlinx.coroutines.MainCoroutineDispatcher.immediate]

*/

val Lifecycle.coroutineScope: LifecycleCoroutineScope

get() {

while (true) {

val existing = mInternalScopeRef.get() as LifecycleCoroutineScopeImpl?

if (existing != null) {

return existing

}

val newScope = LifecycleCoroutineScopeImpl(

this,

SupervisorJob() + Dispatchers.Main.immediate

)

if (mInternalScopeRef.compareAndSet(null, newScope)) {

newScope.register()

return newScope

}

}

}

Lifecycle的coroutineScope也是扩展属性,它是一个LifecycleCoroutineScope。从注释可以看到,在Lifecycle被销毁之后,这个协程会跟着取消。这里首先会从mInternalScopeRef中取之前存入的缓存,如果没有再生成一个LifecycleCoroutineScopeImpl放进去,并调用LifecycleCoroutineScopeImpl的register函数。这里的mInternalScopeRef是Lifecycle类里面的一个属性: AtomicReference<Object> mInternalScopeRef = new AtomicReference<>(); (AtomicReference可以让一个对象保证原子性)。这里使用AtomicReference当然是为了线程安全。

既然生成的是LifecycleCoroutineScopeImpl,那么就先来看看这个东西是什么

internal class LifecycleCoroutineScopeImpl(

override val lifecycle: Lifecycle,

override val coroutineContext: CoroutineContext

) : LifecycleCoroutineScope(), LifecycleEventObserver {

init {

// in case we are initialized on a non-main thread, make a best effort check before

// we return the scope. This is not sync but if developer is launching on a non-main

// dispatcher, they cannot be 100% sure anyways.

if (lifecycle.currentState == Lifecycle.State.DESTROYED) {

coroutineContext.cancel()

}

}

fun register() {

//启了个协程,当前Lifecycle的state大于等于INITIALIZED,就注册一下Lifecycle的观察者,观察生命周期

launch(Dispatchers.Main.immediate) {

if (lifecycle.currentState >= Lifecycle.State.INITIALIZED) {

lifecycle.addObserver(this@LifecycleCoroutineScopeImpl)

} else {

coroutineContext.cancel()

}

}

}

override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {

//观察到当前生命周期小于等于DESTROYED,那么就移除当前这个观察者并且取消协程

if (lifecycle.currentState <= Lifecycle.State.DESTROYED) {

lifecycle.removeObserver(this)

coroutineContext.cancel()

}

}

}

在上面的代码中,有2个重要的函数:register和onStateChanged。register函数是在初始化LifecycleCoroutineScopeImpl的时候调用的,先在register函数中添加一个观察者用于观察生命周期的变化,然后在onStateChanged函数中判断生命周期到DESTROYED时就移除观察者并且取消协程。

有个小细节,为啥register函数中能直接启协程?是因为LifecycleCoroutineScopeImpl继承了LifecycleCoroutineScope,,而LifecycleCoroutineScope实现了CoroutineScope接口(其实是在LifecycleCoroutineScopeImpl中实现的)。

public abstract class LifecycleCoroutineScope internal constructor() : CoroutineScope {

internal abstract val lifecycle: Lifecycle

}

现在我们流程理清楚了,lifecycleScope使用时会构建一个协程,同时会观察组件的生命周期,在适当的时机(DESTROYED)取消协程。

在上面的实例我们见过一段代码:

//方式1

lifecycleScope.launchWhenStarted {

repeat(100000) {

delay(100)

tvText.text = “$it”

}

}

//方式2

lifecycleScope.launch {

whenStarted {

repeat(100000) {

delay(100)

tvText.text = “$it”

}

}

}

可以直接通过lifecycleScope提供的launchWhenCreated、launchWhenStarted、launchWhenResumed在相应的生命周期时执行协程。

点进去看一下

abstract class LifecycleCoroutineScope internal constructor() : CoroutineScope {

internal abstract val lifecycle: Lifecycle

/**

  • Launches and runs the given block when the [Lifecycle] controlling this

  • [LifecycleCoroutineScope] is at least in [Lifecycle.State.CREATED] state.

  • The returned [Job] will be cancelled when the [Lifecycle] is destroyed.

  • @see Lifecycle.whenCreated

  • @see Lifecycle.coroutineScope

*/

fun launchWhenCreated(block: suspend CoroutineScope.() -> Unit): Job = launch {

lifecycle.whenCreated(block)

}

/**

  • Launches and runs the given block when the [Lifecycle] controlling this

  • [LifecycleCoroutineScope] is at least in [Lifecycle.State.STARTED] state.

  • The returned [Job] will be cancelled when the [Lifecycle] is destroyed.

  • @see Lifecycle.whenStarted

  • @see Lifecycle.coroutineScope

*/

fun launchWhenStarted(block: suspend Coroutine
Scope.() -> Unit): Job = launch {

lifecycle.whenStarted(block)

}

/**

  • Launches and runs the given block when the [Lifecycle] controlling this

  • [LifecycleCoroutineScope] is at least in [Lifecycle.State.RESUMED] state.

  • The returned [Job] will be cancelled when the [Lifecycle] is destroyed.

  • @see Lifecycle.whenResumed

  • @see Lifecycle.coroutineScope

*/

fun launchWhenResumed(block: suspend CoroutineScope.() -> Unit): Job = launch {

lifecycle.whenResumed(block)

}

}

原来这些函数就是LifecycleOwner的扩展属性lifecycleScope所返回的LifecycleCoroutineScope类里面的函数。这几个函数里面啥也没干,直接调用了lifecycle对应的函数

/**

  • Runs the given block when the [Lifecycle] is at least in [Lifecycle.State.CREATED] state.

  • @see Lifecycle.whenStateAtLeast for details

*/

suspend fun Lifecycle.whenCreated(block: suspend CoroutineScope.() -> T): T {

return whenStateAtLeast(Lifecycle.State.CREATED, block)

}

/**

  • Runs the given block when the [Lifecycle] is at least in [Lifecycle.State.STARTED] state.

  • @see Lifecycle.whenStateAtLeast for details

*/

suspend fun Lifecycle.whenStarted(block: suspend CoroutineScope.() -> T): T {

return whenStateAtLeast(Lifecycle.State.STARTED, block)

}

/**

  • Runs the given block when the [Lifecycle] is at least in [Lifecycle.State.RESUMED] state.

  • @see Lifecycle.whenStateAtLeast for details

*/

suspend fun Lifecycle.whenResumed(block: suspend CoroutineScope.() -> T): T {

return whenStateAtLeast(Lifecycle.State.RESUMED, block)

}

这几个函数原来是suspend函数,并且是扩展Lifecycle的函数。它们最终都调用到了whenStateAtLeast函数,并传入了执行协程的最小的生命周期状态标志(minState)。

suspend fun Lifecycle.whenStateAtLeast(

minState: Lifecycle.State,

block: suspend CoroutineScope.() -> T

) = withContext(Dispatchers.Main.immediate) {

val job = coroutineContext[Job] ?: error(“when[State] methods should have a parent job”)

val dispatcher = PausingDispatcher()

val controller =

LifecycleController(this@whenStateAtLeast, minState, dispatcher.dispatchQueue, job)

try {

//执行协程

withContext(dispatcher, block)

} finally {

//收尾工作 移除生命周期观察

controller.finish()

}

}

@MainThread

internal class LifecycleController(

private val lifecycle: Lifecycle,

private val minState: Lifecycle.State,

private val dispatchQueue: DispatchQueue,

parentJob: Job

) {

private val observer = LifecycleEventObserver { source, _ ->

if (source.lifecycle.currentState == Lifecycle.State.DESTROYED) {

//DESTROYED->取消协程

handleDestroy(parentJob)

} else if (source.lifecycle.currentState < minState) {

dispatchQueue.pause()

} else {

//执行

dispatchQueue.resume()

}

}

init {

// If Lifecycle is already destroyed (e.g. developer leaked the lifecycle), we won’t get

// an event callback so we need to check for it before registering

// see: b/128749497 for details.

if (lifecycle.currentState == Lifecycle.State.DESTROYED) {

handleDestroy(parentJob)

} else {

//观察生命周期变化

lifecycle.addObserver(observer)

}

}

@Suppress(“NOTHING_TO_INLINE”) // avoid unnecessary method

private inline fun handleDestroy(parentJob: Job) {

parentJob.cancel()

finish()

}

/**

  • Removes the observer and also marks the [DispatchQueue] as finished so that any remaining

  • runnables can be executed.

*/

@MainThread

fun finish() {

//移除生命周期观察者

lifecycle.removeObserver(observer)

//标记已完成 并执行剩下的可执行的Runnable

dispatchQueue.finish()

}

}

whenStateAtLeast也是一个Lifecycle的扩展函数,核心逻辑是在LifecycleController中添加了LifecycleObserver来监听生命周期状态,通过状态来决定是暂停执行还是恢复执行,或者是取消执行。当执行完成之后,也就是finally那里,从执行LifecycleController的finish进行收尾工作:移除生命周期监听,开始执行余下的任务。

执行完成一次,就会移除生命周期观察者,相当于我们写到launchWhenResumed之类的函数里面的闭包只会被执行一次。执行完成之后,即使再经过onPause->onResume也不会再次执行。

4. liveData

在我们平时使用LiveData的过程中,可能会涉及到这种场景:去请求网络拿结果,然后通过LiveData将数据转出去,在Activity里面收到通知,然后更新UI。非常常见的场景,这种情况下,我们可以通过官方的liveData构造器函数来简化上面的场景代码。

4.1 使用

val netData: LiveData = liveData {

//观察的时候在生命周期内,则会马上执行

val data = getNetData()

emit(data)

}

//将耗时任务切到IO线程去执行

private suspend fun getNetData() = withContext(Dispatchers.IO) {

//模拟网络耗时

delay(5000)

//模拟返回结果

“{}”

}

在上面的例子中,getNetData()是一个suspend函数。使用LiveData构造器函数异步调用getNetData(),然后使用emit()提交结果。在Activity那边如果观察了这个netData,并且处于活动状态,那么就会收到结果。我们知道,suspend函数需要在协程作用域中调用,所以liveData的闭包里面也是有协程作用域的。

有个小细节,如果组件在观察此netData时刚好处于活动状态,那么liveData闭包里面的代码会立刻执行。

除了上面这种用法,还可以在liveData里面发出多个值。

val netData2: LiveData = liveData {

delay(3000)

val source = MutableLiveData().apply {

value = “11111”

}

val disposableHandle = emitSource(source)

delay(3000)

disposableHandle.dispose()

val source2 = MutableLiveData().apply {

value = “22222”

}

val disposableHandle2 = emitSource(source2)

}

需要注意的是,后一个调用emitSource的时候需要把前一个emitSource的返回值调用一下dispose函数,切断。

4.2 liveData的底层实现

老规矩,Ctrl+鼠标左键 点进去看源码

@UseExperimental(ExperimentalTypeInference::class)

fun liveData(

context: CoroutineContext = EmptyCoroutineContext,

timeoutInMs: Long = DEFAULT_TIMEOUT,

@BuilderInference block: suspend LiveDataScope.() -> Unit

): LiveData = CoroutineLiveData(context, timeoutInMs, block)

//咱们在liveData后面的闭包里面写的代码就是传给了这里的block,它是一个suspend函数,有LiveDataScope的上下文

首先,映入眼帘的是liveData函数居然是一个全局函数,这意味着你可以在任何地方使用它,而不局限于Activity或者ViewModel里面。

其次,liveData函数返回的是一个CoroutineLiveData对象?居然返回的是一个对象,没有在这里执行任何代码。那我的代码是在哪里执行的?

这就得看CoroutineLiveData类的代码了

internal class CoroutineLiveData(

context: CoroutineContext = EmptyCoroutineContext,

timeoutInMs: Long = DEFAULT_TIMEOUT,

block: Block

) : MediatorLiveData() {

private var blockRunner: BlockRunner?

private var emittedSource: EmittedSource? = null

init {

// use an intermediate supervisor job so that if we cancel individual block runs due to losing

// observers, it won’t cancel the given context as we only cancel w/ the intention of possibly

// relaunching using the same parent context.

val supervisorJob = SupervisorJob(context[Job])

// The scope for this LiveData where we launch every block Job.

// We default to Main dispatcher but developer can override it.

// The supervisor job is added last to isolate block runs.

val scope = CoroutineScope(Dispatchers.Main.immediate + context + supervisorJob)

blockRunner = BlockRunner(

liveData = this,

block = block,

timeoutInMs = timeoutInMs,

scope = scope

) {

blockRunner = null

}

}

internal suspend fun emitSource(source: LiveData): DisposableHandle {

clearSource()

val newSource = addDisposableSource(source)

emittedSource = newSource

return newSource

}

internal suspend fun clearSource() {

emittedSource?.disposeNow()

emittedSource = null

}

override fun onActive() {

super.onActive()

blockRunner?.maybeRun()

}

override fun onInactive() {

super.onInactive()

blockRunner?.cancel()

}

}

里面代码比较少,主要就是继承了MediatorLiveData,然后在onActive的时候执行BlockRunner的maybeRun函数。BlockRunner的maybeRun里面执行的实际上就是我们在liveData里面写的代码块,而onActive方法实际上是从LiveData那里继承过来的,当有一个处于活跃状态的观察者监听LiveData时会被调用。

这就解释得通了,我上面的案例中是在Activity的onCreate(处于活跃状态)里面观察了netData,所以liveData里面的代码会被立刻执行。

//typealias 类型别名

//在下面的BlockRunner中会使用到这个,这个东西用于承载我们在liveData后面闭包里面的代码

internal typealias Block = suspend LiveDataScope.() -> Unit

/**

  • Handles running a block at most once to completion.

*/

internal class BlockRunner(

private val liveData: CoroutineLiveData,

private val block: Block,

private val timeoutInMs: Long,

private val scope: CoroutineScope,

private val onDone: () -> Unit

) {

@MainThread

eNow()

emittedSource = null

}

override fun onActive() {

super.onActive()

blockRunner?.maybeRun()

}

override fun onInactive() {

super.onInactive()

blockRunner?.cancel()

}

}

里面代码比较少,主要就是继承了MediatorLiveData,然后在onActive的时候执行BlockRunner的maybeRun函数。BlockRunner的maybeRun里面执行的实际上就是我们在liveData里面写的代码块,而onActive方法实际上是从LiveData那里继承过来的,当有一个处于活跃状态的观察者监听LiveData时会被调用。

这就解释得通了,我上面的案例中是在Activity的onCreate(处于活跃状态)里面观察了netData,所以liveData里面的代码会被立刻执行。

//typealias 类型别名

//在下面的BlockRunner中会使用到这个,这个东西用于承载我们在liveData后面闭包里面的代码

internal typealias Block = suspend LiveDataScope.() -> Unit

/**

  • Handles running a block at most once to completion.

*/

internal class BlockRunner(

private val liveData: CoroutineLiveData,

private val block: Block,

private val timeoutInMs: Long,

private val scope: CoroutineScope,

private val onDone: () -> Unit

) {

@MainThread

Kotlin 协程与架构组件一起使用及底层原理分析,音视频开发前景相关推荐

  1. linux ucontext 类型,协程:posix::ucontext用户级线程实现原理分析 | WalkerTalking

    在听完leader的课程后,对其中协程的实现方式有了基本的了解,无论的POSIX的ucontex,boost::fcontext,还是libco,都是通过保存和恢复寄存器状态,来进行各个协程上下文的保 ...

  2. Kotlin 协程调度切换线程是时候解开真相了

    前言 协程系列文章: 一个小故事讲明白进程.线程.Kotlin 协程到底啥关系? 少年,你可知 Kotlin 协程最初的样子? 讲真,Kotlin 协程的挂起/恢复没那么神秘(故事篇) 讲真,Kotl ...

  3. 一个小故事讲明白进程、线程、Kotlin 协程到底啥关系?

    前言 协程系列文章: 一个小故事讲明白进程.线程.Kotlin 协程到底啥关系? 少年,你可知 Kotlin 协程最初的样子? 讲真,Kotlin 协程的挂起/恢复没那么神秘(故事篇) 讲真,Kotl ...

  4. 大型Android项目架构:基于组件化+模块化+Kotlin+协程+Flow+Retrofit+Jetpack+MVVM架构实现WanAndroid客户端

    前言:苟有恒,何必三更眠五更起:最无益,莫过一日曝十日寒. 前言 之前一直想写个 WanAndroid 项目来巩固自己对 Kotlin+Jetpack+协程 等知识的学习,但是一直没有时间.这里重新行 ...

  5. pdf 深入理解kotlin协程_Kotlin协程实现原理:挂起与恢复

    今天我们来聊聊Kotlin的协程Coroutine. 如果你还没有接触过协程,推荐你先阅读这篇入门级文章What? 你还不知道Kotlin Coroutine? 如果你已经接触过协程,但对协程的原理存 ...

  6. android 协程,Android 上的 Kotlin 协程

    协程是一种并发设计模式,您可以在 Android 平台上使用它来简化异步执行的代码.协程是在版本 1.3 中添加到 Kotlin 的,它基于来自其他语言的既定概念. 在 Android 上,协程有助于 ...

  7. kotlin协程_使Kotlin协程无缝采用的5个技巧

    kotlin协程 After successfully adopting coroutines in my prod project I think it is time to share 5 tip ...

  8. 扔物线--Kotlin协程训练营2期-2

    笔记仅做自己学习用,方便自己复习知识.若正好可以帮助到Viewer,万分欣喜~ 若博客侵权,扔物线大大不允许放上面,麻烦告知 本文是扔物线Kotlin第二期协程训练营的第二篇文章 没看过第一篇文章的可 ...

  9. pdf 深入理解kotlin协程_协程初探

    Hello,各位朋友,小笨鸟我回来了! 近期学习了Kotlin协程相关的知识,感觉这块技术在项目中的可应用性很大,对项目的开发效率和维护成本有较大的提升.于是就考虑深入研究下相关概念和使用方式,并引入 ...

最新文章

  1. Nibiru Open Day,OZO 遇见 DigiArtist 国际数字艺术展
  2. transformer详解 大牛 wmathor
  3. 【一周入门MySQL—5】
  4. Oracle数据库分组函数详解
  5. Java关于文件上传的一个例子
  6. docker启动,重启,关闭命令
  7. 标题在上边框中的html(fieldset标签)
  8. `if __name__ == __main__`模块运行代码管理
  9. 在线mod计算机,计算机系中有关mod的常识(全).doc
  10. 『数据可视化』基于Python的数据可视化工具
  11. android Camera相关问题及NV12剪裁旋转
  12. 文件管理之:打包、压缩
  13. Mac新手必备技巧之如何关闭Mac屏幕亮度自动调节功能
  14. Windows中的SysWow64文件夹
  15. 关于locale的设定
  16. 新媒体运营教程:名字都没起好,凭什么让用户关注你?
  17. vue 提交form表单
  18. 移动app html手势实现的,移动app交互设计:如何把“手势流”装进手机
  19. VB与C#的区别(转载)
  20. 计算机算法设计与分析期末考试试卷,算法设计与分析期末考试卷及答案a

热门文章

  1. OpenStack云平台搭建(3) | 部署Glance
  2. 《笨办法学python3》再笨的人都能学会python,附PDF,拿走不谢
  3. 尝试解决cocos2dx字体模糊时的一点收获
  4. Half a million dollars is or are a lot of money?
  5. java做可视化界面_利用JAVA编写可视化界面
  6. [Effective C++ --014]在资源管理类中小心copying行为
  7. 百度云生态分享日 | AI技术实践与应用沙龙活动成功举办
  8. python去掉两边空格,Python去除字符串两端空格的方法
  9. R的内存管理和垃圾清理
  10. 分布式事务开山之作——《深入理解分布式事务:原理与实战》草图曝光!!