BlockingGet block UI thread RxJava 2
Asked Answered
G

3

10

I am dealing with the problem.

I am trying to call RxJava in the sync manner, however doing that results in blocking the Main thread.

Here is my code

   @Override
    public Single<SettingsBundle> getSettings() {
        SettingsBundle settingsModel = mSettingsManager.getSettings();
        return Single.just(settingsModel).map(mSettingsMapper);
    }

And here is my sync call

   @Override
    public SettingsBundle getSettingsSync() {
        return getSettings().blockingGet();
    }

When calling the getSettingsSync the Main thread is blocked, however sometimes it works fine, what is more problematic.

I have tried something like that

@Override
public SettingsBundle getSettingsSync() {
    return getSettings()
            .subscribeOn(Schedulers.newThread())
            .observeOn(AndroidSchedulers.mainThread())
            .blockingGet();
}

But it stills remains blocked.

What I am doing wrong, I would be grateful for any help.

Thanks.

Gesundheit answered 6/10, 2017 at 21:59 Comment(4)
A blocking all will block until there's data. Do not use one on the UI thread. Either have another thread do it, or use a non-blocking call.Suitcase
What is your problem exactly? The blockingGet() call will block the current thread until the data is available, this is the expected behavior. What do you want to achieve?Sharper
@GergelyKőrössy , it doesn't get released causing my thread to stuckGesundheit
If you don't want to block the UI thread, then don't use blockingGet which has "blocking" in its nameTacita
C
20

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.

Camshaft answered 4/1, 2018 at 20:8 Comment(1)
Isn't that while "result" in onCreate is waiting to be initialized by the result of this single, the main thread is blocked?Ceria
S
5
.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.

Spawn answered 7/10, 2017 at 14:13 Comment(0)
B
0

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()

Bergh answered 10/10, 2018 at 5:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.