Android 防止同时执行两个挂起函数的一部分
我在ViewModel中并行启动了两种挂起方法:Android 防止同时执行两个挂起函数的一部分,android,kotlin,flow,stateflow,Android,Kotlin,Flow,Stateflow,我在ViewModel中并行启动了两种挂起方法: init { viewModelScope.launch(Dispatchers.Default) { launch { loadTotalCirculation() } launch { loadMarketPrice() } } } private suspend fun loadTotalCirculation() { val totalCirculation = bitcoinCh
init {
viewModelScope.launch(Dispatchers.Default) {
launch { loadTotalCirculation() }
launch { loadMarketPrice() }
}
}
private suspend fun loadTotalCirculation() {
val totalCirculation = bitcoinChartsRepository.getTotalCirculation(5, TimeUnit.HOURS)
_viewState.value = _viewState.value.copy(totalCirculation = chartViewEntityMapper(totalCirculation))
}
private suspend fun loadMarketPrice() {
val marketPrice = bitcoinChartsRepository.getMarketPrice(27, TimeUnit.DAYS)
_viewState.value = _viewState.value.copy(marketPrice = chartViewEntityMapper(marketPrice))
}
但是,我希望防止在这两个方法中同时执行
\u viewState.value=\u viewState.value.copy…
部分。实现这一点的最佳方法是什么?有几种同步并行协同路由的可能性。可能最简单的方法是创建一个单线程上下文,类似于主线程或使用。注意这个互斥是专门为coutroutines设计的,它不是来自Javastdlib的
单线程上下文:
val context = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
private suspend fun loadTotalCirculation() {
val totalCirculation = bitcoinChartsRepository.getTotalCirculation(5, TimeUnit.HOURS)
withContext (context) {
_viewState.value = _viewState.value.copy(totalCirculation = chartViewEntityMapper(totalCirculation))
}
}
private suspend fun loadMarketPrice() {
val marketPrice = bitcoinChartsRepository.getMarketPrice(27, TimeUnit.DAYS)
withContext (context) {
_viewState.value = _viewState.value.copy(marketPrice = chartViewEntityMapper(marketPrice))
}
}
或者,您可以通过:withContext(Dispatchers.main)
重用主线程,而不是创建自己的线程
互斥:
val mutex = Mutex()
private suspend fun loadTotalCirculation() {
val totalCirculation = bitcoinChartsRepository.getTotalCirculation(5, TimeUnit.HOURS)
mutex.withLock {
_viewState.value = _viewState.value.copy(totalCirculation = chartViewEntityMapper(totalCirculation))
}
}
private suspend fun loadMarketPrice() {
val marketPrice = bitcoinChartsRepository.getMarketPrice(27, TimeUnit.DAYS)
mutex.withLock {
_viewState.value = _viewState.value.copy(marketPrice = chartViewEntityMapper(marketPrice))
}
}
使用主线程或互斥体可能是首选,因为如果我们创建自己的线程,我们需要确保在不再需要它时正确地停止/关闭它
您可以从官方文档中阅读本文的更多内容:有几种同步并行协同路由的可能性。可能最简单的方法是创建一个单线程上下文,类似于主线程或使用。注意这个互斥是专门为coutroutines设计的,它不是来自Javastdlib的 单线程上下文:
val context = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
private suspend fun loadTotalCirculation() {
val totalCirculation = bitcoinChartsRepository.getTotalCirculation(5, TimeUnit.HOURS)
withContext (context) {
_viewState.value = _viewState.value.copy(totalCirculation = chartViewEntityMapper(totalCirculation))
}
}
private suspend fun loadMarketPrice() {
val marketPrice = bitcoinChartsRepository.getMarketPrice(27, TimeUnit.DAYS)
withContext (context) {
_viewState.value = _viewState.value.copy(marketPrice = chartViewEntityMapper(marketPrice))
}
}
或者,您可以通过:withContext(Dispatchers.main)
重用主线程,而不是创建自己的线程
互斥:
val mutex = Mutex()
private suspend fun loadTotalCirculation() {
val totalCirculation = bitcoinChartsRepository.getTotalCirculation(5, TimeUnit.HOURS)
mutex.withLock {
_viewState.value = _viewState.value.copy(totalCirculation = chartViewEntityMapper(totalCirculation))
}
}
private suspend fun loadMarketPrice() {
val marketPrice = bitcoinChartsRepository.getMarketPrice(27, TimeUnit.DAYS)
mutex.withLock {
_viewState.value = _viewState.value.copy(marketPrice = chartViewEntityMapper(marketPrice))
}
}
使用主线程或互斥体可能是首选,因为如果我们创建自己的线程,我们需要确保在不再需要它时正确地停止/关闭它
您可以从官方文档中阅读本文的更多内容:您可以使用,但是当您使用
viewModelScope
时,并发性不应该是一个问题,因为它有Dispatchers.Main.immediate
的支持,所以这两个值修改都将以任何方式在主UI线程上进行。嗨,Pawel,这是一个伟大的观点!但是,我在默认调度程序上启动协同路由,这样它们就可以并发运行。我现在已经更新了上面的代码。您可以使用,但是当您使用viewModelScope
时,并发性不应该是一个问题,因为它由Dispatchers.Main.immediate
支持,所以这两个值修改都将以任何方式发生在主UI线程上。嗨,Pawel,这是一个伟大的观点!但是,我在默认调度程序上启动协同路由,这样它们就可以并发运行。我现在已经更新了上面的代码。谢谢!我现在已经使用了互斥解决方案,但也尝试了您建议的另一种方法,即使用主调度程序上下文。我来看看这两种方法的优缺点。这实际上是一个很好的问题:优缺点是什么。我没有足够的信心完全回答这个问题,但我的想法是:我通常避免使用互斥体,因为它们会产生更复杂、可读性更低的代码。任务队列对我来说更自然,所以:参与者模型、事件循环或单线程执行器——它们都以类似的方式工作。在这种特殊情况下,我会说互斥是一种方式。互斥正是它设计的目的。它不依赖于任何外部机械,也没有任何副作用。其他解决方案需要一些外部支持。谢谢!我现在已经使用了互斥解决方案,但也尝试了您建议的另一种方法,即使用主调度程序上下文。我来看看这两种方法的优缺点。这实际上是一个很好的问题:优缺点是什么。我没有足够的信心完全回答这个问题,但我的想法是:我通常避免使用互斥体,因为它们会产生更复杂、可读性更低的代码。任务队列对我来说更自然,所以:参与者模型、事件循环或单线程执行器——它们都以类似的方式工作。在这种特殊情况下,我会说互斥是一种方式。互斥正是它设计的目的。它不依赖于任何外部机械,也没有任何副作用。其他解决方案需要一些外部支持。