CalledFromWrongThreadException 即使使用 AndroidSchedulers.mainThread()

CalledFromWrongThreadException even when using AndroidSchedulers.mainThread()

好的,我们实现了一个 MVP 层,很好地展示并使用 RxJava 和 RxAndroid。我们以 this 为例,并以此为基础。

当 Presenter 被调用开始执行时,它会向 Model Interactor 提交一个 Subscriber。 Interactor 创建一个 Observable 并设置 observeOn(Schedulers.io())subscribeOn(AndroidSchedulers.mainThread())。这样(我们认为)当调用返回到 Subscriber(在 Presenter 中)时,每个调用都将在 UI 线程上。在 Subscriber 中,我们将数据绑定到视图。但是,这会引发 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.access1(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.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.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.access0(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.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.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

堆栈跟踪实际上在此时中断。

当然我们可以在视图中手动在 UI 线程上 运行 它,但是当我们设置 subscribeOn(AndroidSchedulers.mainThread()) 时就没有必要了,不是吗?我们以前没有遇到过这个问题。我们是不是漏掉了什么?

更多实施细节: 我们将 Dagger2 用于 DI,Interactor 在 Module 中创建,并通过构造函数获取 Schedulers。

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

Presenter通过构造函数注入获取Interactor,Presenter通过Component.

注入View

不确定你在那里做什么,但只是提醒和澄清一下:

subscribeOn 方法指定将在其上执行 onSubscribe 方法的线程。

observeOn 方法指定 onNext/onError/ 所在的线程onCompleted 将被执行。

你说的是 - "Interactor creates an Observable and sets observeOn(Schedulers.io()) and subscribeOn(AndroidSchedulers.mainThread())."你可能混淆了这两种方法。