Android 构建可管理生命周期的应用(二)

在前面第一篇有聊过

  • LifecycleOwner 是一个接口,表示某个类拥有一个 Lifecycle

  • LifecycleRegistryLifecycle 类的一个具体实现,它提供了管理生命周期状态的方法

  • 还举例传统分式中 ViewModelLiveData 如何跟随 FragmentActivity 中的Lifecycle生命周期工作的

今天我们聊,在现代应用中,另一个组件协程,如何如何跟随 FragmentActivity 中的Lifecycle生命周期工作的

先来看一下典型的例子

kotlin 复制代码
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    viewLifecycleOwner.lifecycleScope.launch {
        repeatOnLifecycle(Lifecycle.State.STARTED) {
            someFlow.collect {
                // 更新 UI
            }
        }
    }
}

背后逻辑就是:

  • 页面可见且处于前台时(STARTED)才开始 collect
  • 页面不可见(变为 STOPPED)时自动取消 collect
  • 页面销毁时自动清理资源

lifecycleScope

kotlin 复制代码
public interface LifecycleOwner {
public val lifecycle: Lifecycle
}

public val LifecycleOwner.lifecycleScope: LifecycleCoroutineScope
    get() = lifecycle.coroutineScope

跟传统方式比较,就是扩展了一个属性*lifecycleScope*

内部是调用 lifecycle.coroutineScope

简单讲一下kotlin 扩展属性,lifecycle.coroutineScope **这段代码可以理解成 lifecycle 该类型的一个对象,访问了它的coroutineScope属性。下面继续看一下源码实现逻辑。

kotlin 复制代码
public val Lifecycle.coroutineScope: LifecycleCoroutineScope
    get() {
        while (true) {
            val existing = internalScopeRef.get() as LifecycleCoroutineScopeImpl?
            if (existing != null) {
                return existing
            }
            val newScope =
                LifecycleCoroutineScopeImpl(this, SupervisorJob() + Dispatchers.Main.immediate)
            if (internalScopeRef.compareAndSet(null, newScope)) {
                newScope.register()
                return newScope
            }
        }
    }

这个协程作用域内部交给了LifecycleCoroutineScopeImpl 它去实现了

kotlin 复制代码
internal class LifecycleCoroutineScopeImpl(
    override val lifecycle: Lifecycle,
    override val coroutineContext: CoroutineContext
) : LifecycleCoroutineScope(), LifecycleEventObserver {
    init {
        if (lifecycle.currentState == Lifecycle.State.DESTROYED) {
            coroutineContext.cancel()
        }
    }

    fun register() {
        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) {
        if (lifecycle.currentState <= Lifecycle.State.DESTROYED) {
            lifecycle.removeObserver(this)
            coroutineContext.cancel()
        }
    }
}

内部先是注册了生命周期

lifecycle.addObserver(this@LifecycleCoroutineScopeImpl)

然后监听生命周期的变化onStateChanged 在页面销毁的时候,解除绑定,协程取消。

lifecycle.currentState <= Lifecycle.State.DESTROYED

所以最外层的协程viewLifecycleOwner.lifecycleScope.launch的生命周期结束是在 Lifecycle.State.DESTROYED 也就是fragment销毁之后

repeatOnLifecycle

kotlin 复制代码
public suspend fun LifecycleOwner.repeatOnLifecycle(
    state: Lifecycle.State,
    block: suspend CoroutineScope.() -> Unit
): Unit = lifecycle.repeatOnLifecycle(state, block)

继续看一下第二次的协程方法,这是一个拓展函数,一样是来自LifecycleOwner,内部实现依旧是交给lifecyclelifecycle.repeatOnLifecycle也是一个拓展函数,分析一下源码实现逻辑

kotlin 复制代码
public suspend fun Lifecycle.repeatOnLifecycle(
    state: Lifecycle.State,
    block: suspend CoroutineScope.() -> Unit
) {
    ...
    coroutineScope {
withContext(Dispatchers.Main.immediate) {
            if (currentState === Lifecycle.State.DESTROYED) return@withContext
            var launchedJob: Job? = null
            var observer: LifecycleEventObserver? = null
            try {
                suspendCancellableCoroutine<Unit> { cont ->
                    val startWorkEvent = Lifecycle.Event.upTo(state)
                    val cancelWorkEvent = Lifecycle.Event.downFrom(state)
                    val mutex = Mutex()
                    observer = LifecycleEventObserver { _, event ->
if (event == startWorkEvent) {
                            launchedJob =
                                this@coroutineScope.launch {
                                    mutex.withLock { coroutineScope { block() } }
}
return@LifecycleEventObserver
                        }
                        if (event == cancelWorkEvent) {
                            launchedJob?.cancel()
                            launchedJob = null
                        }
                        if (event == Lifecycle.Event.ON_DESTROY) {
                            cont.resume(Unit)
                        }
                    }
this@repeatOnLifecycle.addObserver(observer as LifecycleEventObserver)
                }
} finally {
                launchedJob?.cancel()
                observer?.let { this@repeatOnLifecycle.removeObserver(it) }
}
        }
}
}

suspendCancellableCoroutine 这是一个挂起函数,它需要我们手动去恢复 cont.resume (Unit)就是恢复逻辑,内部实现是注册了生命周期观察者 addObserver(observer as LifecycleEventObserver)

继续把代码简化一下,看看LifecycleEventObserver生命周期变化相关逻辑,

如果我们设置的是repeatOnLifecycle(Lifecycle.State.STARTED)

ini 复制代码
// LifecycleEventObserver
if (STARTED == startWorkEvent) {
    launchedJob =
        this@coroutineScope.launch {
            mutex.withLock { coroutineScope { block() } }
}
return@LifecycleEventObserver
}
if (ON_STOP == cancelWorkEvent) {
    launchedJob?.cancel()
    launchedJob = null
}
if (event == Lifecycle.Event.ON_DESTROY) {
    cont.resume(Unit)
}

也就是页面可见的时候,执行协成代码块,也就是

arduino 复制代码
someFlow.collect {
    // 更新 UI
}

页面不可见的时候,取消协程代码块执行

页面销毁的时候*ON_DESTROY,手动恢复协程cont. resume*(Unit),相当于协程结束了

所以,someFlow.collect更新UI的逻辑,在*ON_STOP会被取消了,跟最外层的协程逻辑是有差异的,最外层是更长的生命周期,它持续到 ON_DESTROY*

repeatOnLifecycle(Lifecycle.State.STARTED)很适合UI更新

相关推荐
_extraordinary_43 分钟前
Java 字符串常量池 +反射,枚举和lambda表达式
android·java·开发语言
alexhilton1 小时前
学会说不!让你彻底学会Kotlin Flow的取消机制
android·kotlin·android jetpack
来来走走1 小时前
Flutter dart运算符
android·前端·flutter
青小莫1 小时前
IDM下载失败常见原因
android
阿华的代码王国2 小时前
【Android】日期选择器
android·xml·java·前端·后端
小墙程序员4 小时前
Android 性能优化(五)Heap Dump 的使用
android·性能优化
阿华的代码王国4 小时前
【Android】RecyclerView实现新闻列表布局(1)适配器使用相关问题
android·xml·java·前端·后端
EngZegNgi4 小时前
Unity —— Android 应用构建与发布
android·unity·自动化·游戏引擎·构建
fatiaozhang95274 小时前
烽火HG680-KX-海思MV320芯片-2+8G-安卓9.0-强刷卡刷固件包
android·电视盒子·刷机固件·机顶盒刷机
LiuYaoheng5 小时前
【Android】使用 Intent 传递对象的两种序列化方式
android·java·笔记·学习