lifecycleScope.launchWhenStarted是否安全?如果它不安全,在什么情况下



在我的应用程序中,我使用协程和流向API发送请求。当请求到来时,我更改了stateFlow的值,以便我的活动中的收集器看到它并完成它的工作。这是一个简单的场景。在android网站(https://developer.android.com/kotlin/flow/stateflow-and-sharedflow(,提出了2种方法。在这种情况下,我应该更喜欢哪种方法?

以下是上述链接中的一段引文

使用launchWhen((函数可以安全地收集StateFlow,因为它们的作用域为ViewModels,使它们在视图转到后台,它们只需向视图通知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()
}
}

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

更新(2023年3月(

Lifecycle.launchWhenX方法和Lifecycle.whenX方法已被弃用,因为在某些情况下,使用暂停调度程序可能会导致资源浪费。建议使用Lifecycle.repeatOnLifecycle。请参阅生命周期版本2.6.0的发行说明。

原始答案

不管怎样,如果视图处于停止状态或任何低于STARTED的状态,collect块都将不起作用。

但流的订阅计数表示有多少订阅者希望收集流。诀窍来了。当视图移动到小于STARTED状态的状态时,collect块将被挂起,但流的订阅计数保持不变,从而将流生成器保留在内存中。但是,如果你采用第二种方法取消作业,那么当你取消作业时,订阅计数就会减少,这将防止流生成器在内存中,这在不需要时是浪费资源。

现在,他们在最后一句中给出的警告是针对除StateFlow之外的其他流量生产者。例如,流生成器函数flow{ //some intensive work }。StateFlow的工作方式不同,因为它只向活动/片段发出UI状态,不包含任何代码块(昂贵的代码(。因此,使用launchWhen函数收集StateFlow是安全的。

在UI状态发射的情况下,这是所需的工作,因为即使片段处于后台且不活动,也需要流来发射更改,但一旦从后台再次恢复,就应该立即获得最新的更改。在这里,StateFlow应该保留在内存中,该内存的作用域为viewmodel。

因为lifecycleScope.launchWhenX已弃用。尝试使用创建一个扩展函数和一个简单的调用。

launchWhenResumed { 
// your Code..
} 

链接(代码(:https://stackoverflow.com/a/75885233/20440272

相关内容

最新更新