Search code examples
androidmultithreadingkotlinandroid-handlerui-thread

Posting to UI thread


I would like to create a new thread in onCreate and communicate with the UI thread using post on a View. However, the posted statements never seem to be run. Here's a small example:

import android.app.Activity
import android.os.Bundle
import android.widget.TextView    
import kotlin.concurrent.*
import org.jetbrains.anko.*

class MainActivity: Activity(), AnkoLogger {
  protected override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    val view = TextView(this)
    setContentView(view)

    thread() {
      info("before post")
      view.post({ info("inside post") })
      info("after post")
    }
  }
}

Looking at the log, I can only see before post and after post, but never inside post.

What am I doing wrong?


Solution

  • The underlying issue actually has nothing to do with Kotlin.

    The problem is that View.post() only schedules its work successfully on the main thread if the view is currently attached to the view hierarchy. The final attach of the view doesn't happen at the time of setContentView(). It happens some time later.

    In the event that the subject view of the post() is not currently attached (as is the case shown in the problem), the View creates a RunQueue for the current thread (stored as a thread local) and schedules the work on that RunQueue.

    So, the problem for the given sample is as follows. Since View.post() is not called on the main thread, it will create a new RunQueue for the current, non-main thread without checking to see if it's being directed by a Looper (as is the main thread). This means the scheduled Runnable essentially goes into a RunQueue that is not processed until a Looper starts. In the case shown here, that Looper is never started, the new thread terminates, and the work is never executed.

    If the new thread with post was delayed until after the view was attached, for example, when a click is registered on it, the post will likely be able to schedule the work on the main thread. But that's not the case here since the post occurs 1) before the view is attached, and 2) on a different non-Looper thread that terminates immediately.