在前面第一篇有聊过
-
LifecycleOwner
是一个接口,表示某个类拥有一个Lifecycle
-
LifecycleRegistry
是Lifecycle
类的一个具体实现,它提供了管理生命周期状态的方法 -
还举例传统分式中
ViewModel
中LiveData
如何跟随Fragment
、Activity
中的Lifecycle
生命周期工作的
今天我们聊,在现代应用中,另一个组件协程,如何如何跟随 Fragment
、Activity
中的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
,内部实现依旧是交给lifecycle
,lifecycle.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更新