Lets talk about a specific example, consider :
abstract class AsyncWriter {
private val handler : Handler
init {
val handlerThread = HandlerThread("AsyncWriter")
handlerThread.start()
handler = Handler(handlerThread.looper)
}
protected abstract fun internalWrite(s: String);
protected abstract fun internalClose()
fun write(s: String) {
handler.post {
internalWrite(s)
}
}
fun close() {
handler.post {
internalClose()
}
}
}
With Handler, since its managing a single thread job queue i can be sure that when the resource is closed, all previously requested writes were written and only then the resource was closed.
Attempting to easily migrate to Kotlin's coroutines :
abstract class AsyncWriter {
protected abstract fun internalWrite(s: String);
protected abstract fun internalClose()
fun write(s: String) {
GlobalScope.launch {
internalWrite(s)
}
}
fun close() {
GlobalScope.launch {
internalClose()
}
}
}
Is quite nice but no longer guarantees resource will close after all previous writes.(1. right?)
There may be some work arounds like :
abstract class AsyncWriter {
protected abstract fun internalWrite(s: String);
protected abstract fun internalClose()
private val d = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
fun write(s: String) {
GlobalScope.launch(d) {
internalWrite(s)
}
}
fun close() {
GlobalScope.launch(d) {
internalClose()
}
}
}
Which im not even sure that will work (2. it wont work right? i think it wont since continuations of all prev non finished writes and the close execution will be in some kind of a race condition)
or this approach which will work i think but will make synchronization overhead over the simple handler approach (3. right?) :
abstract class AsyncWriter {
protected abstract fun internalWrite(s: String);
protected abstract fun internalClose()
private val m = Mutex()
fun write(s: String) {
GlobalScope.launch {
m.withLock {
internalWrite(s)
}
}
}
fun close() {
GlobalScope.launch {
m.withLock {
internalClose()
}
}
}
}
- What is the prefered kotlin tool to migrate from using a handler for this use case? or is handler still the best way to do that?
Thanks!
NOTE: I numbered the questions along the way for easy reference