Использование глобального изменяемого общего состояния действительно не рекомендуется для параллельного кода.
Вы можете попробовать что-то вроде этого, хотя:
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()
}