I'm re-factoring my Android code from Java to Kotlin using coroutines but i did not find an easy way to rewrite callback-based code to suspended functions.
A basic example would be an alert popup that returns a result, in Javascript it would be something like this:
let value = prompt("please insert a value")
console.log("Value:"+value)
I would translate in Kotlin to something like:
class MainActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
//Standard activity initialization
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//Actual code...
launch {
val value = resolvable<String>(UI) { success, error ->
//Build a simple popup prompt with AlertDialog
val input = EditText(this@MainActivity)
val builder = AlertDialog.Builder(this@MainActivity)
.setTitle("please insert a value")
.setView(input)
.setPositiveButton("Ok",{ dialog, id ->
success(input.text.toString())//This lambda returns the value
})
val dialog = builder.create()
dialog.show()
}
println("Value:"+ value)
}
//...
}
}
The resolvable is a custom function i developed for this purpuse, here's the source code:
import kotlinx.coroutines.experimental.DefaultDispatcher
import kotlinx.coroutines.experimental.cancelAndJoin
import kotlinx.coroutines.experimental.launch
import java.util.concurrent.Semaphore
import kotlin.coroutines.experimental.CoroutineContext
suspend fun <T> resolvable(
context: CoroutineContext = DefaultDispatcher,
block: suspend (success:(T?)->Unit,error:(Throwable)->Unit) -> Unit
):T?{
var result:T? = null
var exception:Throwable? = null
val semaphore = Semaphore(0)
val job = launch(context){
block({r:T? -> {
result=r
semaphore.release()
}},{e:Throwable -> {
exception=e
semaphore.release()
}})
}
semaphore.acquire()
job.cancelAndJoin()
if(exception!=null)
throw exception!!
return result
}
I quickly developed the resolvable function (keep in mind it's a quick draft) using lambdas and semaphores but i don't know if there are any pre-existing function (i could not found any) or can be optimized or has any drawback/problems.
Thanks.
It looks that you are trying to reinvent suspendCoroutine
function. I'd suggest to replace your resolvable
function with invocation of suspendCoroutine
to get the kind of functionality you are looking for:
//Actual code...
launch(UI) {
val value = suspendCoroutine<String> { cont ->
//Build a simple popup prompt with AlertDialog
val input = EditText(this@MainActivity)
val builder = AlertDialog.Builder(this@MainActivity)
.setTitle("please insert a value")
.setView(input)
.setPositiveButton("Ok",{ dialog, id ->
cont.resume(input.text.toString()) //!!! Resume here
})
val dialog = builder.create()
dialog.show()
}
println("Value:"+ value)
}
If you perform "extract function" refactoring around suspendCoroutine
block and name the resulting suspending function prompt
, then you can write your code in a style that is very similar to JS.
You can also consider using suspendCancellebleCoroutine
instead of a plain suspendCoroutine
. This way you can support cancellation of the launched coroutine and install a handler to close your dialog when it is cancelled.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With