Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

handler.postDelayed from within runnable shows syntax error in Kotlin - Android

private val progressTask = Runnable {
    runOnUiThread { if (!tvMessage.text.isEmpty()) tvMessage.text = "" }
    pbLoading.progress++
    when {
        pbLoading.progress == 600 -> finalFunction()
        pbLoading.progress % 20 == 0 -> runOnUiThread {
            tvMessage.text = messages[pbLoading.progress / 20]
        }
    }
    handler.postDelayed(this, 1000)
}

This code is giving me an syntax error under the this keyword. Saying that this error points to my activity rather than the runnable itself. How do I fix this?

like image 427
Adifyr Avatar asked Feb 23 '18 06:02

Adifyr


2 Answers

You can’t do this with a regular lambda. In order to make this refer to the Runnable, use the object syntax:

val runnable = object : Runnable {
    override fun run() {
        println("$this runs in a runnable")
    }
}

It’s slightly more verbose and that’s the price you pay.

like image 122
s1m0nw1 Avatar answered Oct 09 '22 19:10

s1m0nw1


Let me offer you a deeper solution to your problem: do yourself a favor and switch to Kotlin coroutines. This is how your code would look with them:

fun showLoadingProgress(tvMessage: TextView, pbLoading: ProgressBar) = launch(UI) {
    if (!tvMessage.text.isEmpty()) tvMessage.text = ""
    with(pbLoading) {
        do {
            delay(1000)
            if (progress++ % 20 == 0) tvMessage.text = messages[progress / 20]
        } while (progress < 600)
        finalFunction()
    }
}

If you're worried that they are still "experimental", that just means their API is still not finalized. JetBrains has already committed to maintain backwards compatibility with the experimental API and I can personally attest to the robustness of its implementation — I have never experienced any issues at all with it.


You mentioned your concern that you also have to pause your progress monitor and then resume it at a later time. With coroutines you'd achieve it as follows:

  1. Within showLoadingProgress() you'll write

    suspendCoroutine { cont -> this.progressMonitorContinuation = cont }
    

    This implies the existence of a var progressMonitorContinuation: Continuation<Unit>?.

  2. When you're ready to resume the progress monitor, write

    val cont = this.progressMonitorContinuation!!
    this.progressMonitorContinuation = null
    launch(UI) { cont.resume(Unit) }
    
like image 29
Marko Topolnik Avatar answered Oct 09 '22 21:10

Marko Topolnik