RxJava Chained Observables和NetworkMainThreadException

时间:2015-07-03 12:31:00

标签: android rx-java

所以我有这段代码:

public Observable<AbstractXMPPConnection> connect(final AbstractXMPPConnection connection) {
    return Observable.<AbstractXMPPConnection>create(subscriber -> {
        try {
            AbstractXMPPConnection connection2 = connection.connect();
            if (connection2.isConnected()) {
                subscriber.onNext(connection2);
                subscriber.onCompleted();
            }
        } catch (SmackException | IOException | XMPPException e) {
            e.printStackTrace();
            subscriber.onError(e);
        }
    })
    .doOnError(throwable -> LOGI("111", "Connection OnError called"));
}


public Observable<AbstractXMPPConnection> connectWithRetry(final AbstractXMPPConnection connection) {
       return connect(connection)
               .retryWhen(attempts -> attempts.zipWith(Observable.range(1, MAX_CONNECTION_TRIES), (throwable, integer) -> new Pair<>(throwable, integer))
                       .flatMap(pair -> {
                           if (pair.second == MAX_LOGIN_TRIES)
                               return Observable.error(pair.first);
                           return Observable.timer(pair.second, TimeUnit.SECONDS);
                       }));
    }


public void connect() {
        assertTrue("To start a connection to the server, you must first call init() method!",
                this.connectionConfig != null);

        connectionHelper.connectWithRetry(connection)
                .observeOn(Schedulers.newThread())
                .subscribeOn(AndroidSchedulers.mainThread())
                .subscribe(new Subscriber<AbstractXMPPConnection>() {
                    @Override
                    public void onCompleted() {
                    }

                    @Override
                    public void onError(Throwable e) {
                        LOGI(TAG, "ConnectionHelper Connection onError\n");

                        /**{@link LoginActivity#onConnectionFailure(OnConnectionFailureEvent)} */
                        MainApplication.getInstance().getBusInstance().post(new OnConnectionFailureEvent());
                    }

                    @Override
                    public void onNext(AbstractXMPPConnection connection) {
                        LOGI(TAG, "ConnectionHelper Connection onNext");
//                        onConnected();
                    }
                });
    }

我对链接可观察量有一些疑问。想象一下这个场景,我有一个连接Observable,有时我会使用它,但我主要使用connectWithRetry() Observable。

我的问题是,如果添加了这个会发生什么:

.observeOn(Schedulers.newThread())
.subscribeOn(AndroidSchedulers.mainThread())

同时connect()connectWithRetry()?在这种情况下,当我打电话 public void connect并指定一个调度程序,之前的那些被忽略了吗?

为什么我会NetworkOnMainThreadException?明确的observeOn(Schedulers.newThread())就在那里,它不应该给我那个错误

2 个答案:

答案 0 :(得分:1)

我先解决您的NetworkOnMainThread问题。

observeOn(Schedulers.newThread())表示将在新线程上观察输出 - 也就是说,订阅者中的代码(onComplete/Error/Next)将在该线程上运行。

subscribeOn(AndroidSchedulers.mainThread()表示订阅将在主线程上发生 - 您创建的observable(connection.connect()等)中的代码是订阅发生时运行的内容。

所以简单地交换调度程序:

.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())

因此,为了解决您的第一个问题,他们不会被忽略,他们只是被错误地使用了。希望你可以看到如果你将类似的调用移动到返回observables的方法中的链中会发生什么:与你已经完成的事情没什么不同。这些电话只是在不同的地方。

那么选择调度程序的位置呢?这取决于你。您可以通过 not 在创建可观察对象的方法中调用subscribeOn来获得更高的清晰度:

 connectionHelper.connectWithRetry(connection)
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())

但是,如果您觉得自己无缘无故地在任何地方调用此功能,则可以在方法中移动subscribeOn调用:

return connect(connection)
           .retryWhen(...)
           .flatMap(...)
           .subscribeOn(Schedulers.io())
           .observeOn(AndroidSchedulers.mainThread());

请注意,这些不必像这样捆绑在一起 - 您可以在方法中subscribeOn,但将observeOn留给任何希望在特定线程上获得结果的来电者

答案 1 :(得分:0)

请尝试使用Schedulers.io()可能会解决问题。