I would like to create a new thread in onCreate
and communicate with the UI thread using post
on a View
. However, the post
ed 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?
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.