提问者:小点点

LifecycleScope.LaunchWhenStarted安全吗?如果不安全,为了什么情况?


在我的应用程序中,我使用coroutine和flow向API发送请求。当请求出现时,我更改了stateFlow的值,以便我的activity中的收集器看到并执行其工作。这是一个简单的场景。在android网站(https://developer.android.com/kotlin/flow/stateflow-and-sharedflow)中,建议了2种方法。在这种情况下,我应该倾向于哪种方法?

以下是上述链接的引文。:

使用launchWhen()函数收集Stateflow是安全的,因为它们的作用域是ViewModel,使它们在视图转到后台时保留在内存中,并且它们只通过通知视图有关UI状态来完成轻量级工作。然而,问题可能会出现在其他做更密集工作的生产者身上。

在这段引文中,说第一种方法是安全的,但在最后一句中有一个警告。那警告是为了什么?我不明白它是否安全。生产者是否继续采用第一种方法?在我的情况下,如果请求还没有来,而用户在后台运行应用程序,制作者是否工作并尝试更新UI?

第一种方法:

class LatestNewsActivity : AppCompatActivity() {
    private val latestNewsViewModel = // getViewModel()

    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        // This coroutine will run the given block when the lifecycle
        // is at least in the Started state and will suspend when
        // the view moves to the Stopped state
        lifecycleScope.launchWhenStarted {
            // Triggers the flow and starts listening for values
            latestNewsViewModel.uiState.collect { uiState ->
                // New value received
                when (uiState) {
                    is LatestNewsUiState.Success -> showFavoriteNews(uiState.news)
                    is LatestNewsUiState.Error -> showError(uiState.exception)
                }
            }
        }
    }
}

第二种方法:

class LatestNewsActivity : AppCompatActivity() {
    ...
    // Coroutine listening for UI states
    private var uiStateJob: Job? = null

    override fun onStart() {
        super.onStart()
        // Start collecting when the View is visible
        uiStateJob = lifecycleScope.launch {
            latestNewsViewModel.uiState.collect { uiState -> ... }
        }
    }

    override fun onStop() {
        // Stop collecting when the View goes to the background
        uiStateJob?.cancel()
        super.onStop()
    }
}

在这种非常简单的情况下,哪种方法更合适?


共1个答案

匿名用户

无论如何,如果视图处于停止状态或低于启动状态,则collection块将不工作。

但是对于流有一个叫做订阅计数的东西,它指示有多少订阅者希望收集该流。诀窍来了。当视图移动到小于STARTED状态的状态时,Collection块将挂起,但流的订阅计数保持不变,这将流生成器保留在内存中。但是如果您采用第二种方法取消作业,则在取消作业时订阅计数将减少,并且会防止流生成器留在内存中,这在不需要时会浪费资源。

现在,他们在最后一句话中给出的警告是针对stateflow以外的其他流生产者的。例如,flow builder函数flow{//Some Consensive work}。StateFlow的工作方式不同,因为它只是向activity/片段发出UI状态,而不包含任何代码块(昂贵的代码)。因此使用launchWhen函数收集StateFlow是安全的。

这是在UI状态发射的情况下所希望的工作,因为您需要流发射更改,即使片段在backstack中且不活动,但当它从backstack中再次还原时,也应该获得最新的更改。在这里,StateFlow应该保留在范围为ViewModel的内存中。

相关问题