title: RxJava: observeOn, subscribeOn, and doFinally, switching between IO and UI thread
body: <p>I am running into an issue where my observable is subscribed on an IO thread and observed on the android main (UI) thread but the <code>doFinally</code> operator is run on the IO thread and it needs to be run on the UI thread.  </p>
  
  <p>The usecase is almost exactly the same as this <a href="https://medium.com/@ValCanBuild/making-rxjava-code-tidier-with-doonsubscribe-and-dofinally-3748f223d32d" rel="nofollow noreferrer">medium article</a>. </p>
  
  <p>I essentially want to show a <code>ProgressBar</code> when the Observable is subscribed to and hide the <code>ProgressBar</code> when the Observable is terminated or finished.</p>
  
  <p>The error I am getting is: <strong>java.lang.IllegalStateException: The current thread must have a looper!</strong></p>
  
  <p>Can anyone help me move the <code>doFinally</code> action back to the UI thread which has a looper?  Or am I missing some other piece of information?</p>
  
  <p><strong>EDIT</strong>
  The usecase workflow is: </p>
  
  <p>-> Launch Activity </p>
  
  <p>-> initialize </p>
  
  <p>-> execute observable stream </p>
  
  <p>-> Start new Activity and finish current activity </p>
  
  <p>-> New activity </p>
  
  <p>-> Start original activity and finish </p>
  
  <p>-> repeat initialize</p>
  
  <p>Thank you very much.</p>
  
  <p>Details:</p>
  
  <ul>
  <li>RxJava 2.0.7</li>
  <li>RxAndroid 2.0.1</li>
  <li>Android sdk min 14 and target 25</li>
  </ul>
  
  <p>Example Code</p>
  
  <pre><code>listUseCase.execute(null)
              .doOnSubscribe(new Consumer&lt;Disposable&gt;() {
                  @Override
                  public void accept(@NonNull Disposable disposable) throws Exception {
                      getView().showLoading(true);
                  }
              })
              .doFinally(new Action() {
                  @Override
                  public void run() throws Exception {
                      getView().showLoading(false);
                  }
              })
              .subscribeOn(schedulerProvider.io())
              .observeOn(schedulerProvider.main())
              .subscribe(
                      new Consumer&lt;List&lt;AccountEntity&gt;&gt;() {
                          @Override
                          public void accept(@NonNull List&lt;AccountEntity&gt; accountEntities) throws Exception {
                              getView().setAccounts(accountEntities);
                          }
                      },
                      new Consumer&lt;Throwable&gt;() {
                          @Override
                          public void accept(@NonNull Throwable throwable) throws Exception {
                              if (isViewAttached()) {
                                  getView().showError(throwable.getMessage());
                              }
                          }
                      }
              );
  </code></pre>
  
  <p>Stack Trace:</p>
  
  <pre><code>FATAL EXCEPTION: RxCachedThreadScheduler-1
    Process: com.example.android.demo.customerfirst.alpha, PID: 16685
    java.lang.IllegalStateException: The current thread must have a looper!
        at android.view.Choreographer$1.initialValue(Choreographer.java:96)
        at android.view.Choreographer$1.initialValue(Choreographer.java:91)
        at java.lang.ThreadLocal$Values.getAfterMiss(ThreadLocal.java:430)
        at java.lang.ThreadLocal.get(ThreadLocal.java:65)
        at android.view.Choreographer.getInstance(Choreographer.java:192)
        at android.animation.ValueAnimator$AnimationHandler.&lt;init&gt;(ValueAnimator.java:600)
        at android.animation.ValueAnimator$AnimationHandler.&lt;init&gt;(ValueAnimator.java:575)
        at android.animation.ValueAnimator.getOrCreateAnimationHandler(ValueAnimator.java:1366)
        at android.animation.ValueAnimator.end(ValueAnimator.java:998)
        at android.graphics.drawable.AnimatedVectorDrawable.stop(AnimatedVectorDrawable.java:439)
        at android.widget.ProgressBar.stopAnimation(ProgressBar.java:1523)
        at android.widget.ProgressBar.onVisibilityChanged(ProgressBar.java:1583)
        at android.view.View.dispatchVisibilityChanged(View.java:8643)
        at android.view.View.setFlags(View.java:9686)
        at android.view.View.setVisibility(View.java:6663)
        at android.widget.ProgressBar.setVisibility(ProgressBar.java:1563)
        at com.example.android.demo.customerfirst.featuresstore.list.ProductListActivity.showLoading(ProductListActivity.java:121)
        at com.example.android.demo.customerfirst.featuresstore.list.ProductListPresenterMediator$3.run(ProductListPresenterMediator.java:56)
        at io.reactivex.internal.operators.observable.ObservableDoFinally$DoFinallyObserver.runFinally(ObservableDoFinally.java:144)
        at io.reactivex.internal.operators.observable.ObservableDoFinally$DoFinallyObserver.onComplete(ObservableDoFinally.java:94)
        at io.reactivex.internal.observers.DisposableLambdaObserver.onComplete(DisposableLambdaObserver.java:73)
        at io.reactivex.internal.observers.DeferredScalarDisposable.complete(DeferredScalarDisposable.java:84)
        at io.reactivex.internal.operators.observable.ObservableFromCallable.subscribeActual(ObservableFromCallable.java:52)
        at io.reactivex.Observable.subscribe(Observable.java:10700)
        at io.reactivex.internal.operators.observable.ObservableDoOnLifecycle.subscribeActual(ObservableDoOnLifecycle.java:33)
        at io.reactivex.Observable.subscribe(Observable.java:10700)
        at io.reactivex.internal.operators.observable.ObservableDoFinally.subscribeActual(ObservableDoFinally.java:45)
        at io.reactivex.Observable.subscribe(Observable.java:10700)
        at io.reactivex.internal.operators.observable.ObservableSubscribeOn$1.run(ObservableSubscribeOn.java:39)
        at io.reactivex.Scheduler$1.run(Scheduler.java:138)
        at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:59)
        at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:51)
        at java.util.concurrent.FutureTask.run(FutureTask.java:237)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:152)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:265)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
        at java.lang.Thread.run(Thread.java:818)
  </code></pre>