Retain observed settings through read failures and retry without default resets
This commit is contained in:
1 parent
e8aeaaf365
commit
61bdf4a6df
2 files changed
+24
No files matched your search
@@ -7,8 +7,11 @@ import kotlinx.coroutines.Deferred
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.retryWhen
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
|
||||
@@ -37,4 +40,13 @@ class SettingsOperations(private val scope: CoroutineScope = CoroutineScope(Supe
|
||||
}
|
||||
fun dismissFailure() { _failed.value = false }
|
||||
suspend fun awaitIdle() { mutex.withLock { } }
|
||||
|
||||
/** Ошибка чтения не публикует defaults поверх последнего значения и не завершает подписку UI. */
|
||||
fun <T> observe(name: String, values: Flow<T>): Flow<T> = values.retryWhen { error, attempt ->
|
||||
if (error is CancellationException || error !is Exception) false else {
|
||||
reportFailure(name, error)
|
||||
delay((250L shl attempt.toInt().coerceIn(0, 7)).coerceAtMost(30_000))
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
+12
@@ -6,6 +6,9 @@ import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.take
|
||||
import kotlinx.coroutines.flow.toList
|
||||
import org.junit.Assert.*
|
||||
import org.junit.Test
|
||||
|
||||
@@ -39,4 +42,13 @@ class SettingsOperationsTest {
|
||||
val waiter = launch { owner.awaitIdle() }; waiter.cancel()
|
||||
gate.complete(Unit); change.await(); assertTrue(saved); assertFalse(change.isCancelled)
|
||||
}
|
||||
@Test fun failedPreferenceObservationPreservesTheLastValueAndCanRecover() = runTest {
|
||||
val owner = SettingsOperations(this) { _, _ -> }; var attempts = 0
|
||||
val values = flow {
|
||||
if (++attempts == 1) { emit(42); throw java.io.IOException("read failed") }
|
||||
emit(43)
|
||||
}
|
||||
assertEquals(listOf(42, 43), owner.observe("preferences", values).take(2).toList())
|
||||
assertTrue(owner.failed.value); assertEquals(2, attempts)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user