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

相关推荐
coderlin_7 小时前
BI布局拖拽 (1) 深入react-gird-layout源码
android·javascript·react.js
2501_915918418 小时前
Fiddler中文版全面评测:功能亮点、使用场景与中文网资源整合指南
android·ios·小程序·https·uni-app·iphone·webview
wen's9 小时前
React Native安卓刘海屏适配终极方案:仅需修改 AndroidManifest.xml!
android·xml·react native
编程乐学10 小时前
网络资源模板--基于Android Studio 实现的聊天App
android·android studio·大作业·移动端开发·安卓移动开发·聊天app
没有了遇见12 小时前
Android 通过 SO 库安全存储敏感数据,解决接口劫持问题
android
hsx66612 小时前
使用一个 RecyclerView 构建复杂多类型布局
android
hsx66612 小时前
利用 onMeasure、onLayout、onDraw 创建自定义 View
android
守城小轩12 小时前
Chromium 136 编译指南 - Android 篇:开发工具安装(三)
android·数据库·redis
whysqwhw13 小时前
OkHttp平台抽象机制分析
android
hsx66614 小时前
Android 内存泄漏避坑
android