Глобальный флаг не запускать функцию приостановки? - PullRequest
0 голосов
/ 02 марта 2020

Мне нужно запустить метод 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

но я думаю, что глобальный флаг не является хорошим решением. Есть ли другой лучший подход?

1 Ответ

1 голос
/ 02 марта 2020

Использование глобального изменяемого общего состояния действительно не рекомендуется для параллельного кода.

Вы можете попробовать что-то вроде этого, хотя:

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