首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >关于launchWhenX和repeatOnLifecycle的问题

关于launchWhenX和repeatOnLifecycle的问题
EN

Stack Overflow用户
提问于 2022-07-11 20:54:18
回答 1查看 247关注 0票数 2

我有以下代码和一些需要回答的问题:

代码语言:javascript
运行
复制
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    lifecycleScope.launchWhenResumed {
        delay(2000)
        Log.d("LifeCycleAware", "launchWhenStarted: before calling")
        val result = differentDispatcher()
        Log.d("LifeCycleAware", "launchWhenStarted: after calling $result")
    }
}

private suspend fun differentDispatcher(): Int =
    withContext(Dispatchers.Default) {
        for (i in 1..5) {
            delay(2000)
            Log.d("LifeCycleAware", "Inside different Dispatcher")
        }
        return@withContext 9
    }

override fun onStart() {
    super.onStart()
    Log.d("LifeCycleAware", "onStart")
}

override fun onStop() {
    super.onStop()
    Log.d("LifeCycleAware", "onStop")
}

据我所知,当生命周期达到恢复状态时,会调用方法(或其中任何一个) launchWhenResumed,而且我还知道,当我将应用程序移到后台时,波纹将停止,但如果它在另一个调度程序中运行子波纹,则不会停止,到目前为止还不错。

因此,在这段代码中,我们确定如果我,在differentDispatcher方法中的循环中间,将应用程序发送到第二,它将继续运行,但是当它完成时,使用launchWhenResumed启动的父波纹将不会恢复,直到它再次恢复状态。

我的第一个疑问是..。如果波纹运动结束后,我回到后台,回到前台,如果我回到了恢复状态,为什么不重新启动呢?

我还知道repeatOnLifecycle方法的存在,如果我把Lifecycle.State.RESUMED状态作为参数传递给它,它每次都会被执行,而且我知道,在这种情况下,如果我回到后台,波纹的执行就会被完全挂起,当我回到前台时,它从一开始就开始了,但是,为什么当我使用launchWhenResumed运行而瓦楞纸结束时,它不会重新开始,而是用repeatOnLifecycle开始执行呢?它在内部做什么不同呢?

我想答案是因为当我从背景切换到前台时,不会再次调用onCreate方法,并且我已经检查过:

代码语言:javascript
运行
复制
override fun onResume() {
    super.onResume()
    lifecycleScope.launchWhenResumed {
        delay(2000)
        Log.d("LifeCycleAware", "launchWhenStarted: before calling")
        val result = differentDispatcher()
        Log.d("LifeCycleAware", "launchWhenStarted: after calling $result")
    }
}

这样它就会重新启动,因为当我从背景切换到前台时,onResume方法确实会再次调用,但是.repeatOnLifecycle方法做了什么魔术?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-07-12 04:35:38

理解launchWhenResumed的关键是将其分解为两个部分,即:一个launch和一个whenResumed块。看看源代码,您就会看到它实际上是这样的:

代码语言:javascript
运行
复制
public fun launchWhenResumed(
    block: suspend CoroutineScope.() -> Unit
): Job = launch { // It does a regular launch
    lifecycle.whenResumed(block) // Then passes your block to whenResumed
}

launch是一次操作--在onCreate()中完成的launch每次对onCreate()的调用都只运行一次。这也是为什么每次点击launch时调用onResume()中的onResume都会启动的原因。

launch的调用以两种方式之一结束:该块中的所有调用正常完成,或者CoroutineScope被取消。对于lifecycleScope,这种取消发生在Lifecycle到达DESTROYED时。

因此,在常规的launch中,工作立即开始,直到一切完成(或者范围被取消),仅此而已。它永远不会再次运行或重新启动。

相反,whenResumed暂停生命周期感知的协同服务的一个例子。

尽管CoroutineScope提供了一种自动取消长期运行的操作的正确方法,但可能还有其他情况,您希望挂起代码块的执行,除非处于某种状态。 如果Lifecycle 至少没有处于所需的最低状态,则在这些块中运行的任何协同线都将被挂起。

因此,whenResumed所做的只是在低于恢复状态时暂停协同代码,本质上意味着,如果您的Lifecycle不再是RESUMED,而不是您的val result = differentDispatcher()实际上立即恢复执行,并且您的结果被传递回您的代码,那么这个结果就是等待您的Lifecycle再次到达RESUMED

因此,whenResumed没有任何“重新启动”功能--就像其他协同代码一样,它只运行给定的代码,然后正常完成。

你说得对,repeatOnLifecycle是一种完全不同的模式。根据可重新启动的生命周期感知协同机制repeatOnLifecycle根本没有任何“暂停”行为:

尽管lifecycleScope提供了一种在生命周期被破坏时自动取消长期运行的操作的正确方法,但您可能还需要在生命周期处于特定状态时,启动代码块的执行,而当生命周期处于另一种状态时,则希望取消。

因此,在repeatOnLifecycle调用中,每次Lifecycle到达RESUMED (或所需的Lifecycle.State )时,都会运行该块。当您低于该状态时,整个块将被完全取消(非常类似于当您的LifecycleOwner到达DESTROYED时--即取消整个协同范围的级别)。

您不会在页面末尾提到这两个API时发出可怕的警告:

警告:更喜欢使用repeatOnLifecycle API来收集流,而不是在launchWhenX API中收集。由于后一个API挂起协同线,而不是在生命周期停止时取消它,因此上游流保持在后台活动,可能会释放新项并浪费资源。

您的differentDispatcher代码继续在后台运行,尽管它位于whenResumed块内,但这被认为是一件坏事--如果该代码执行更昂贵的操作,比如检查用户的位置(保持GPS ),它将继续耗尽系统资源和用户的电池,即使您不是RESUMED

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72944569

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档