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更新

相关推荐
g_i_a_o_giao1 小时前
Android8 binder源码学习分析笔记(一)
android·java·笔记·学习·binder·安卓源码分析
翻滚丷大头鱼1 小时前
android 四大组件—BroadcastReceiver
android
人生游戏牛马NPC1号2 小时前
学习 Android (二十) 学习 OpenCV (五)
android·opencv·学习
2501_916008892 小时前
uni-app iOS 日志与崩溃分析全流程 多工具协作的实战指南
android·ios·小程序·https·uni-app·iphone·webview
文 丰2 小时前
【AndroidStudio】官网下载免安装版,AndroidStudio压缩版的配置和使用
android
WillWolf_Wang2 小时前
Linux 编译 Android 版 QGroundControl 软件并运行到手机上
android·linux·智能手机
fatiaozhang95272 小时前
数码视讯TR100-OTT-G1_国科GK6323_安卓9_广东联通原机修改-TTL烧录包-可救砖
android·xml·电视盒子·刷机固件·机顶盒刷机
撬动未来的支点2 小时前
【Android】内核及子系统
android
2501_915921433 小时前
iOS混淆工具实战 在线教育直播类 App 的课程与互动安全防护
android·安全·ios·小程序·uni-app·iphone·webview
前行的小黑炭6 小时前
Android Flow的其他使用:stateIn和冷流(普通Flow)
android·kotlin