Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CalledFromWrongThreadException even when using AndroidSchedulers.mainThread()

Alright, we implemented a MVP layer for, well presentation and use RxJava and RxAndroid with it. We took this as example and built upon it.

When the Presenter is called to start acting, it submits a Subscriber to the Model Interactor. The Interactor creates an Observable and sets observeOn(Schedulers.io()) and subscribeOn(AndroidSchedulers.mainThread()). That way (we thought) when the call comes back to the Subscriber (within the Presenter) every call would be on the UI thread. Within the Subscriber we bind data to the view. However, this raises a CalledFromWrongThreadException:

07-28 09:12:48.844  17424    17566         AndroidRuntime  E  FATAL EXCEPTION: RxCachedThreadScheduler-1
07-28 09:12:48.844  17424    17566         AndroidRuntime  E  Process: [PACKAGE NAME], PID: 17424
07-28 09:12:48.844  17424    17566         AndroidRuntime  E  java.lang.IllegalStateException: Fatal Exception thrown on Scheduler.Worker thread.
07-28 09:12:48.844  17424    17566         AndroidRuntime  E  at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:62)
07-28 09:12:48.844  17424    17566         AndroidRuntime  E  at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422)
07-28 09:12:48.844  17424    17566         AndroidRuntime  E  at java.util.concurrent.FutureTask.run(FutureTask.java:237)
07-28 09:12:48.844  17424    17566         AndroidRuntime  E  at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:152)
07-28 09:12:48.844  17424    17566         AndroidRuntime  E  at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:265)
07-28 09:12:48.844  17424    17566         AndroidRuntime  E  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
07-28 09:12:48.844  17424    17566         AndroidRuntime  E  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
07-28 09:12:48.844  17424    17566         AndroidRuntime  E  at java.lang.Thread.run(Thread.java:818)
07-28 09:12:48.844  17424    17566         AndroidRuntime  E  Caused by: rx.exceptions.OnErrorFailedException: Error occurred when trying to propagate error to Observer.onError
07-28 09:12:48.844  17424    17566         AndroidRuntime  E  at rx.observers.SafeSubscriber._onError(SafeSubscriber.java:201)
07-28 09:12:48.844  17424    17566         AndroidRuntime  E  at rx.observers.SafeSubscriber.onError(SafeSubscriber.java:111)
07-28 09:12:48.844  17424    17566         AndroidRuntime  E  at rx.observers.SafeSubscriber.onNext(SafeSubscriber.java:137)
07-28 09:12:48.844  17424    17566         AndroidRuntime  E  at rx.internal.operators.OperatorSubscribeOn$1$1$1.onNext(OperatorSubscribeOn.java:76)
07-28 09:12:48.844  17424    17566         AndroidRuntime  E  at rx.internal.operators.NotificationLite.accept(NotificationLite.java:150)
07-28 09:12:48.844  17424    17566         AndroidRuntime  E  at rx.internal.operators.OperatorObserveOn$ObserveOnSubscriber.pollQueue(OperatorObserveOn.java:205)
07-28 09:12:48.844  17424    17566         AndroidRuntime  E  at rx.internal.operators.OperatorObserveOn$ObserveOnSubscriber$2.call(OperatorObserveOn.java:159)
07-28 09:12:48.844  17424    17566         AndroidRuntime  E  at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55)
07-28 09:12:48.844  17424    17566         AndroidRuntime  E  ... 7 more
07-28 09:12:48.844  17424    17566         AndroidRuntime  E  Caused by: rx.exceptions.CompositeException: 2 exceptions occurred.
07-28 09:12:48.844  17424    17566         AndroidRuntime  E  ... 15 more
07-28 09:12:48.844  17424    17566         AndroidRuntime  E  Caused by: rx.exceptions.CompositeException$CompositeExceptionCausalChain: Chain of Causes for CompositeException In Order Received =>
07-28 09:12:48.844  17424    17566         AndroidRuntime  E  at android.util.Log.getStackTraceString(Log.java:499)
07-28 09:12:48.844  17424    17566         AndroidRuntime  E  at com.android.internal.os.RuntimeInit.Clog_e(RuntimeInit.java:59)
07-28 09:12:48.844  17424    17566         AndroidRuntime  E  at com.android.internal.os.RuntimeInit.access$200(RuntimeInit.java:43)
07-28 09:12:48.844  17424    17566         AndroidRuntime  E  at com.android.internal.os.RuntimeInit$UncaughtHandler.uncaughtException(RuntimeInit.java:91)
07-28 09:12:48.844  17424    17566         AndroidRuntime  E  at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:693)
07-28 09:12:48.844  17424    17566         AndroidRuntime  E  at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:690)
07-28 09:12:48.844  17424    17566         AndroidRuntime  E  at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:66)
07-28 09:12:48.844  17424    17566         AndroidRuntime  E  ... 7 more
07-28 09:12:48.844  17424    17566         AndroidRuntime  E  Caused by: java.lang.IllegalStateException: Method call should happen from the main thread.
07-28 09:12:48.844  17424    17566         AndroidRuntime  E  at com.squareup.picasso.Utils.checkMain(Utils.java:136)
07-28 09:12:48.844  17424    17566         AndroidRuntime  E  at com.squareup.picasso.RequestCreator.into(RequestCreator.java:615)
07-28 09:12:48.844  17424    17566         AndroidRuntime  E  at com.squareup.picasso.RequestCreator.into(RequestCreator.java:601)
07-28 09:12:48.844  17424    17566         AndroidRuntime  E  at com.nextmarkets.next.education.view.TradingIdeaHistoryFragment.setCoachAvatar(TradingIdeaHistoryFragment.java:94)
07-28 09:12:48.844  17424    17566         AndroidRuntime  E  at com.nextmarkets.next.education.TradingIdeaHistoryPresenter$TradingIdeaHistorySubscriber.onNext(TradingIdeaHistoryPresenter.java:55)
07-28 09:12:48.844  17424    17566         AndroidRuntime  E  at com.nextmarkets.next.education.TradingIdeaHistoryPresenter$TradingIdeaHistorySubscriber.onNext(TradingIdeaHistoryPresenter.java:38)
07-28 09:12:48.844  17424    17566         AndroidRuntime  E  at rx.observers.SafeSubscriber.onNext(SafeSubscriber.java:130)
07-28 09:12:48.844  17424    17566         AndroidRuntime  E  at rx.internal.operators.OperatorSubscribeOn$1$1$1.onNext(OperatorSubscribeOn.java:76)
07-28 09:12:48.844  17424    17566         AndroidRuntime  E  at rx.internal.operators.NotificationLite.accept(NotificationLite.java:150)
07-28 09:12:48.844  17424    17566         AndroidRuntime  E  at rx.internal.operators.OperatorObserveOn$ObserveOnSubscriber.pollQueue(OperatorObserveOn.java:205)
07-28 09:12:48.844  17424    17566         AndroidRuntime  E  at rx.internal.operators.OperatorObserveOn$ObserveOnSubscriber$2.call(OperatorObserveOn.java:159)
07-28 09:12:48.844  17424    17566         AndroidRuntime  E  at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55)
07-28 09:12:48.844  17424    17566         AndroidRuntime  E  ... 7 more
07-28 09:12:48.844  17424    17566         AndroidRuntime  E  Caused by: android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
07-28 09:12:48.844  17424    17566         AndroidRuntime  E  at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:7062)
07-28 09:12:48.844  17424    17566         AndroidRuntime  E  at android.view.ViewRootImpl.requestChildFocus(ViewRootImpl.java:3098)
07-28 09:12:48.844  17424    17566         AndroidRuntime  E  at android.view.ViewGroup.requestChildFocus(ViewGroup.java:678)
07-28 09:12:48.844  17424    17566         AndroidRuntime  E  at android.view.ViewGroup.requestChildFocus(ViewGroup.java:678)
07-28 09:12:48.844  17424    17566         AndroidRuntime  E  at android.view.ViewGroup.requestChildFocus(ViewGroup.java:678)
07-28 09:12:48.844  17424    17566         AndroidRuntime  E  at android.view.ViewGroup.requestChildFocus(ViewGroup.java:678)
07-28 09:12:48.844  17424    17566         AndroidRuntime  E  at andro

The stacktrace actually cuts off at this point.

Of course we could just run it on the UI thread manually in the View, but that shouldn't be necessary when we set subscribeOn(AndroidSchedulers.mainThread()), should it? We've done this before without a problem. Are we missing something?

Some more implementation details: We use Dagger2 for DI and the Interactor is created in a Module and gets the Schedulers via the constructor.

    @Provides
    MyInteractor provideMyInteractor() {
        return new MyInteractorImpl(Schedulers.io(), AndroidSchedulers.mainThread());
    }

The Presenter gets the Interactor via constructor injection and the Presenter is injected into the View via the Component.

like image 674
robocab Avatar asked Dec 15 '22 12:12

robocab


1 Answers

Not sure what you're doing in there but just to remind and clarify :

subscribeOn method specifies thread on which onSubscribe method will be executed.

observeOn method specifies thread on which onNext/onError/onCompleted will be executed.

You're saying - "Interactor creates an Observable and sets observeOn(Schedulers.io()) and subscribeOn(AndroidSchedulers.mainThread())." You may have confused these two methods.

like image 99
krp Avatar answered Jan 07 '23 13:01

krp