Chris Fillmore
01/07/2022, 12:05 PMStateFlow<Job>
, so that connection lifecycles can be observed, cancelled, reconnected, etc. I have an Android app which connects to several websocket endpoints on different protocols, including plain websockets, socketio, action cable, graphql subscriptions, so being able to define a common pattern like this would be useful to me. More in 🧵Chris Fillmore
01/07/2022, 12:05 PMfun main(args: Array<String>) = runBlocking {
println("Program start")
val jobLoop = LazyJobLoop(Dispatchers.Default)
jobLoop.job.collect {
withContext(it) {
println("In withContext")
}
}
Unit
}
interface JobLoop : CoroutineScope {
val job: StateFlow<Job>
}
class LazyJobLoop(
coroutineContext: CoroutineContext,
) : JobLoop, CoroutineScope by CoroutineScope(coroutineContext) {
private val _job = MutableStateFlow(launchJob())
override val job = _job.asStateFlow()
private fun launchJob() = launch(start = CoroutineStart.LAZY) {
println("In job")
}
}
Chris Fillmore
01/07/2022, 12:06 PMException in thread "main" java.lang.IllegalStateException: Job is still new or active: LazyStandaloneCoroutine{New}@544a2ea6
Chris Fillmore
01/07/2022, 12:07 PMCoroutineContext
, then I will get the above exceptionChris Fillmore
01/07/2022, 12:12 PMjobLoop.job.value.start()
when they want the job to start (or in my case, when I want to open the websocket connection.
Or it could be used like:
jobLoop.job
.onEach { job ->
// Maybe do some suspending work beforehand,
// like fetch another resource, get a fresh token, whatever
job.start()
}
.launchIn(myClientScope)
Chris Fillmore
01/07/2022, 12:13 PMChris Fillmore
01/07/2022, 12:17 PMlaunch { }
without the start
parameter, then immediately suspend, but I would need to introduce something else to suspend on, complicating the design.