BlockingGet block UI thread RxJava 2 BlockingGet block UI thread RxJava 2 multithreading multithreading

BlockingGet block UI thread RxJava 2


TL;TR

never use observeOn(AndroidSchedulers.mainThread()) with blockingGet()


Long version

The output for:

class MainActivity : AppCompatActivity() {    override fun onCreate(savedInstanceState: Bundle?) {        super.onCreate(savedInstanceState)        setContentView(R.layout.activity_main)        val result =                Single.just("Hello")                .subscribeOn(Schedulers.io())               // .observeOn(AndroidSchedulers.mainThread())                .map {                    println("1. blockingGet `$it` thread: ${Thread.currentThread()}")                    return@map it                }                .blockingGet()        println("2. blockingGet `$result` thread: ${Thread.currentThread()}")    }}

is

 1. blockingGet `Hello` thread: Thread[RxCachedThreadScheduler-1,5,main] 2. blockingGet `Hello` thread: Thread[main,5,main]

As you can see result was generated on main thread (line 2), the map function was execute in the RxCachedThreadScheduler thread.

With the line .observeOn(AndroidSchedulers.mainThread()) decommented the blockingGet() never return and all is stucked.


.observeOn(AndroidSchedulers.mainThread()).blockingGet();

The problem exists in this specific combination of operators. AndroidSchedulers schedules code to run on the main thread, however the blockingGet() stops more code from executing on that thread. Simply put AndroidSchedulers and the blocking operators of RxJava do not work well together.

Since the android scheduler might be used in the construction of the observable this means any use of the blocking* operators on the main thread will be prone to deadlocks regardless of what you try to do.


If you really need a function to run on the main thread and also need it to be synchronous, then you could do something like this:

  1. If this is the main thread (Looper.myLooper() == Looper.getMainLooper()), then run func()

  2. If not on the main thread, then you can use the combination of observeOn(AndroidSchedulers.mainThread()) with blockingGet()