Last active
October 11, 2022 23:32
-
-
Save DevNebulae/a0ead640f3c9047bb1495cceb35e7e33 to your computer and use it in GitHub Desktop.
Lifecycle-aware class intended to be used to handle periodic tasks. Its main purpose is to handle periodic tasks in a viewmodel (e.g. refreshing a list from a web service)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Uses packages: | |
// * org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.6.4 | |
import kotlinx.coroutines.CoroutineScope | |
import kotlinx.coroutines.Job | |
import kotlinx.coroutines.delay | |
import kotlinx.coroutines.isActive | |
import kotlinx.coroutines.launch | |
import kotlin.time.Duration | |
class TickHandler { | |
private var job: Job? = null | |
fun start(scope: CoroutineScope, interval: Duration, block: suspend () -> Unit) { | |
job = scope.launch { | |
while (isActive) { | |
block() | |
delay(interval) | |
} | |
} | |
} | |
fun stop() { | |
job?.cancel() | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Uses packages: | |
// * org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.4 | |
// * io.kotest:kotest-runner-junit5:5.5.1 | |
// * io.kotest:kotest-assertions-core:5.5.1 | |
import io.kotest.core.spec.style.FunSpec | |
import io.kotest.core.test.testCoroutineScheduler | |
import io.kotest.matchers.shouldBe | |
import kotlinx.coroutines.ExperimentalCoroutinesApi | |
import kotlinx.coroutines.test.TestCoroutineScheduler | |
import kotlin.time.Duration | |
import kotlin.time.Duration.Companion.milliseconds | |
import kotlin.time.Duration.Companion.seconds | |
@OptIn(ExperimentalCoroutinesApi::class, ExperimentalStdlibApi::class) | |
class TickHandlerTest : FunSpec({ | |
val tickHandler = TickHandler() | |
test("Periodically emits events").config( | |
coroutineTestScope = true, | |
timeout = 10.seconds | |
) { | |
// Arrange | |
// An initial delay is added to allow the ticker to immediately emit an event when the | |
// ticker is started (probably has to do with initializing the (scope of a) test). | |
val initialDelay = 100.milliseconds | |
val interval = 1.seconds | |
var tickCounter = 0 | |
// Act | |
tickHandler.start(this, interval) { tickCounter++ } | |
testCoroutineScheduler.advanceTimeBy(interval * 4 + initialDelay) | |
// Assert | |
// It should be 5 after 4 seconds, as it immediately emits an event when the ticker is | |
// started. | |
tickCounter shouldBe 5 | |
// Tear down | |
tickHandler.stop() | |
} | |
}) | |
@OptIn(ExperimentalCoroutinesApi::class) | |
private fun TestCoroutineScheduler.advanceTimeBy(delay: Duration) = | |
advanceTimeBy(delay.inWholeMilliseconds) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment