首页 > 解决方案 > 全局标志不启动挂起功能?

问题描述

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

但我认为全局标志不是好的解决方案。还有其他更好的方法吗?

标签: androidkotlinkotlin-coroutines

解决方案


并发代码确实不建议使用全局可变共享状态。

不过,您可以尝试这样的事情:

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()
}

推荐阅读