0

I am facing this error from RxJava

Android “Only the original thread that created a view hierarchy can touch its views.”

code i used

Log.d(TAG, "stratObserving:qw ${Thread.currentThread()}")
(application as? App)?.relayPages
                ?.doAfterNext{
                    hideLoading()
                }
                ?.observeOn(AndroidSchedulers.mainThread())
                ?.subscribe({
                   "data found ${it.size}".log()
                    pageAdapter.setPageList(it)
                    rvAyahsPages.scrollToPosition(pos)
                    "data pageAdapter ${pageAdapter.itemCount} , ${Thread.currentThread()}".log()
                    foundState()
                }, {
                    "error ${it.message}".log()
                })
                ?.addTo(model.bg)
 private fun foundState() {
        spShowAyahs?.visibility = View.GONE
        tvNoQuranData?.visibility = View.GONE
        rvAyahsPages?.visibility = View.VISIBLE
        "found $rvAyahsPages $spShowAyahs".log()
    }

however

Log.d(TAG, "stratObserving:qw ${Thread.currentThread()}") print Thread [main,5,main]

and

Log.d(TAG, "stratObserving:qw ${Thread.currentThread()}") print Thread [main,5,main]

[Note]

This Question differs from "Android “Only the original thread that created a view hierarchy can touch its views.”" answers that the solution was to run on MainThread but here it actually run on MainThread

[Edit] problem was of ordering of operator so replace doAfterNext with observeOn.

Mahmoud Mabrok
  • 1,362
  • 16
  • 24

1 Answers1

0

As @fraggjkee and @EpicPandaForce already mentioned, the problem is here:

(application as? App)?.relayPages
                ?.doAfterNext{
                    hideLoading()
                }

What is the problem: Android “Only the original thread that created a view hierarchy can touch its views

This issue is raised, when someone tries to update the UI state from a non UI-thread. The UI-eventloop is single-threaded. Therefore it is forbidden, that other Threads update UI-state (e.g. View properties etc.)

Why is observeOn not working?

(application as? App)?.relayPages
                ?.doAfterNext{
                    hideLoading()
                }
                ?.observeOn(AndroidSchedulers.mainThread())

ObserveOn switches the thread from one operator to another in the observable. When relayPages emits an value, it will pass through doAfterNext on any given thread, most likely the subscribing thread. After passing through doAfterNext the exmit will go through the ObserveOn-operator. This is there the magic happens. In this operator the emit (onNext) action will be enqueued as a runnable in the UI-eventloop (AndroidSchedulers#mainThread).

For further instruction please have a look at this explanation: http://tomstechnicalblog.blogspot.de/2016/02/rxjava-understanding-observeon-and.html

Problem

The #doAfterNext operator is invoked from a non-UI-thread, which tries to change some UI-state.

Resolution

All UI-state changes must be invoked from an UI-thread. Therefore you have to make sure, that this is the case.

(application as? App)?.relayPages
                // observeOn switches the thread from X to the UI-eventloop
                ?.observeOn(AndroidSchedulers.mainThread())
                // hideLoading is called from UI-eventloop, everything should be fine
                ?.doAfterNext{
                    hideLoading()
                }

Summary

ObserveOn must be place in the operator-chain, before the UI-state is changed.

Sergej Isbrecht
  • 3,842
  • 18
  • 27