Amio.io
Amio.io

Reputation: 21545

Observable OnCompleted cannot update UI

I am trying to Toast finishing a service call. However in the onComplete method I receive this exception:

java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()

It is thrown from SafeSubscriber#onNext(T args) which looks like this:

/**
     * Provides the Subscriber with a new item to observe.
     * <p>
     * The {@code Observable} may call this method 0 or more times.
     * <p>
     * The {@code Observable} will not call this method again after it calls either {@link #onCompleted} or
     * {@link #onError}.
     * 
     * @param args
     *          the item emitted by the Observable
     */
    @Override
    public void onNext(T args) {
        try {
            if (!done) {
                actual.onNext(args);
            }
        } catch (Throwable e) {
            // we handle here instead of another method so we don't add stacks to the frame
            // which can prevent it from being able to handle StackOverflow
            Exceptions.throwIfFatal(e);
            // handle errors if the onNext implementation fails, not just if the Observable fails
            onError(e);
        }
    }

This is the code snippet from my code where the problem rises:

 NetworkService.aService()
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread()) 
                    .flatmap(anotherCall)
                    .subscribe(new Subscriber<AddCommentResponse>() {
                @Override
                public void onCompleted() {
                    Toast.makeText(...).show();
                    navigateBack();
                }

                // etc. ...

Is the problem that I cannot update UI from onCompleted method? Or where should I handle UI operations?

Upvotes: 3

Views: 1890

Answers (3)

Amio.io
Amio.io

Reputation: 21545

Originally:

NetworkService.aService()
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread()) 
                    .flatmap(anotherCall)

After this change it is working:

NetworkService.aService()
                    .flatmap(anotherCall)
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread()) 

Upvotes: 5

dwursteisen
dwursteisen

Reputation: 11515

Maybe theanotherCall observe on another thread. Move the observeOn (on the android main thread) after the flatMap call.

Upvotes: 9

Karan
Karan

Reputation: 2130

NetworkService is on worker Thread. You are calling makeText(..) from the worker thread, which should be called from UI thread. Try creating a Handler and toasting from inside it.

ActivityContext.runOnUiThread(new Runnable() { 
  public void run() { 
Toast.makeText(activity, "Hello", Toast.LENGTH_SHORT).show();
  } 
}); 

Upvotes: 1

Related Questions