android - 全局标志不启动挂起功能?
问题描述
getFuelPrice
只有当它之前没有启动时,我才需要启动方法。为此,我使用全局标志isStartGetFuelPrice
smt 像这样:
for (currentPass in 0..10) {
// some code here
viewModelScope.launch(Dispatchers.Main) {
if (!isStartedGetFuelPrice) {
currentCheck = getFuelPrice(currentCheck)
}
}
}
在迭代 1 上,方法getFuelPrice
开始,但在迭代 2 上不能开始。函数getFuelPrice
必须只调用一次。
和这个:
suspend fun getFuelPrice(currentRecognizedCheck: Check): Check {
isStartedGetFuelPrice = true
// some logic here
isStartedGetFuelPrice = false
return currentRecognizedCheck
但我认为全局标志不是好的解决方案。还有其他更好的方法吗?
解决方案
并发代码确实不建议使用全局可变共享状态。
不过,您可以尝试这样的事情:
data class Once(private val block: suspend () -> Unit) {
private val ran = AtomicBoolean(false)
suspend fun run() {
if (ran.compareAndSet(false, true)) {
block()
}
}
}
然后:
val once = Once { getFuelPrice() }
for (currentPass in 0..10) {
// some code here
viewModelScope.launch(Dispatchers.Main) {
once.run()
}
}
你也可以Once
让它返回一个值,但为此你需要使用 Kotlin Mutex
:
data class Once<out T : Any>(private val block: suspend () -> T) {
private val mutex = Mutex()
private lateinit var r : T
suspend fun run(): T {
mutex.lock()
if (!this::r.isInitialized) {
r = block()
}
mutex.unlock()
return r
}
}
甚至:
suspend fun run(): T {
return mutex.withLock {
if (!this::r.isInitialized) {
r = block()
}
r
}
}
如果你不喜欢互斥体,还有另一个技巧:
class Once<T>(block: suspend () -> T) {
private val r = GlobalScope.async(start = CoroutineStart.LAZY) {
block()
}
suspend fun run() = r.await()
}
推荐阅读
- ms-access - 在 VBA 中运行 SQL 字符串?
- python - 如何确定是否为 Selenium + Python 加载了一些 HTML 元素?
- javascript - 添加其他一些 JS 代码后,javascript 确认对话框不起作用
- python - 如何连接两个numpy数组
- python - SQL 的 Python 抽象层
- c# - 无法加载文件或程序集“System.Net.Http.Formatting”
- jmeter - jmeter kafka消费者抛出错误为[ClassCastException:[Ljava.lang.String; 无法转换为 java.util.List]
- tsql - SSMS - 自动完成参数(智能感知)
- r - R:堆叠条形图的ggplot,绘图和自动调整
- javascript - Javascript:如何在新窗口中安全地打开用户提供的 URL