abandoned
abandoned

Reputation: 61

Why does the Observable not create on the right thread?

Observable observable = Observable.from(backToArray(downloadWebPage("URL")))
            .map(new Func1<String[], Pair<String[], String[]>>() {
                @Override
                public Pair<String[], String[]> call(String[] of) {
                    return new Pair<>(of,
                            backToArray(downloadWebPage("URL" + of[0])).get(0));
                }
            });

    observable.subscribeOn(Schedulers.newThread()).observeOn(AndroidSchedulers.mainThread()).subscribe(
            (new Observer<Pair>() {

                @Override
                public void onCompleted() {
                    // Update user interface if needed
                }

                @Override
                public void onError(Throwable t) {
                    // Update user interface to handle error
                }

                @Override
                public void onNext(Pair p) {
                   offices.add(new Office((String[]) p.first, (String[]) p.second));
                }
           }));

This runs and i get android.os.NetworkOnMainThreadException. I would expect it to run a new thread as set by the subscribeOn() method.

Upvotes: 1

Views: 228

Answers (3)

Harsh Parikh
Harsh Parikh

Reputation: 3845

You should change from

**observable.subscribeOn(Schedulers.newThread())**

to

**observable.subscribeOn(Schedulers.io())**

Upvotes: 0

LordRaydenMK
LordRaydenMK

Reputation: 13321

You can use defer() to postpone the calling of downloadWebPage to the moment when you subscribe to the observable.

Example:

private Object slowBlockingMethod() { ... }

public Observable<Object> newMethod() {
    return Observable.defer(() -> Observable.just(slowBlockingMethod()));
}

Source

Upvotes: 4

david.mihola
david.mihola

Reputation: 13002

Assuming that the actual network request is happening in downloadWebPage(), the error is in the first line of your code:

Observable observable = Observable.from(backToArray(downloadWebPage("http://api.ataxcloudapp.com/v1/franchise/listing/?location=" + ZIPCode)))

This is equivalent to:

String[] response = downloadWebPage("http://api.ataxcloudapp.com/v1/franchise/listing/?location=" + ZIPCode)

Observable observable = Observable.from(backToArray(response))

This should make it clear that downloadWebPage is executed - on the main thread - before any Observable is even created, let alone subscribed to. RxJava cannot change the semantics of Java in this regard.

What you can do however is something like this (not tested, but should be about right):

Observable observable = Observable.create(new Observable.OnSubscribe<String[]>() {
        @Override
        public void call(final Subscriber<? super String[]> subscriber) {
            final String[] response = downloadWebPage("http://api.ataxcloudapp.com/v1/franchise/listing/?location=" + ZIPCode);
            if (! subscriber.isUnsubscribed()) {
                subscriber.onNext(backToArray(response));
                subscriber.onCompleted();
            }
        }
)

Now your network request will happen only after the Observable is subscribed to, and will be moved to a the thread you specify in subscribeOn().

Upvotes: 4

Related Questions