dalek

Dalek is a tiny (~10 LOC) finite state machine that helps you manage the UI state of your app when running async/breakable tasks.
It's powered by Coroutines Flow and works on Android & JVM.
Why Dalek?
Daleks are a fictional extraterrestrial race of mutants portrayed in Doctor Who.
They are creatures that live inside a tank-like robotic shell, and this is basically how this library works: your code (the "creature") is wrapped and executed inside a state machine (the "robotic shell").
"EXTERMINATE! EXTERMINATE! EXTERMINATE!"
(Any Dalek will say that)
Motivation
Let's imagine the following scenario: you need to retrieve a Post object from a REST API, something like:
class PostRepository {
suspend fun getPost(id: String): Post {
// async api call
// serialization
// error handling
}
}
It's an asynchronous operation that can take a while to complete and can fail (TimeoutException, IOException, SerializationException...). But wait, there's more: you need to keep the UI updated so your user knows what's going on.
This is a nightmare, right? Calm down! Dalek is here to help :robot:
Usage
1. Wrap your code inside Dalek
To start using Dalek, you just need to wrap your existing code inside it.
Dalek will run your code inside a suspend fun and return a Flow<DalekEvent<T>>, where T is the output of your code (you can return null, Unit and Any, I won't judge you).
class MyViewModel(private val repository: PostRepository) : ViewModel() {
fun getPost(id: String): Flow<DalekEvent<Post>> =
Dalek(Dispatchers.IO) {
repository.getPost(id)
}
}
2. Handle the UI events
Dalek will emit the following events:
Start: always emittedSuccess(value: T): only emitted when your code is successfully executedFailure(exception: Throwable): only emitted when an exception is thrownFinish: always emitted
class MyActivity : AppCompatActivity() {
private fun loadPost(id: String) {
viewModel.getPost(id)
.collectIn(lifecycleScope) { event ->
when (event) {
is Start -> setLoading(true)
is Success -> showPost(event.value)
is Failure -> showError(event.exception)
is Finish -> setLoading(false)
}
}
}
}
