从ConnectableFlowable调用connect时出现NetworkOnMainThreadException

时间:2017-10-30 00:12:06

标签: android rx-java retrofit2 rx-java2

我在处理 ConnectableFlowable 和线程时遇到问题:

我的改装服务返回一个ConnectableFlowable:

service.searchBeers(config.getKey(), name)
                        .map(Mappers.SEARCH_MAPPER).publish();

在我的Interactor类中,我订阅了它以将数据添加到Firebase数据库,然后我将ConnectableFlowable返回给演示者。我调用了方法subscribeOn,unsubscribeOn和observeOn传递IO线程,因为Firebase插入不需要在主线程中执行。

@Override
    public Flowable<LocalType<List<Beer>>> searchBeers(String query) {
        ConnectableFlowable<LocalType<List<Beer>>> connectableFlowable = (ConnectableFlowable<LocalType<List<Beer>>>)
                remote.search(query);

        connectableFlowable.unsubscribeOn(schedulerProvider.io()).subscribeOn(schedulerProvider.io()).observeOn
                (schedulerProvider.io()).subscribe(onNext,
                onError);

        return connectableFlowable;
    }

在我的Presenter中,我订阅了它来更新View,所以我调用observeOn并传递schedulerProvider.ui()(这是mainThread的包装器)。

@Override
public void search(String query) {

    ConnectableFlowable<LocalType<List<Beer>>> flowable = (ConnectableFlowable<LocalType<List<Beer>>>)
            searchInteractor.searchBeers(query);
    flowable.subscribeOn(schedulerProvider.io()).observeOn(schedulerProvider.ui()).unsubscribeOn
            (schedulerProvider.io())
            .subscribe(
                    beerListData -> searchView.showSearchResult(beerListData.getData()),
                    error -> searchView.showSearchError(error)
            );

    flowable.connect();
}

但是当它调用flowable.connect时会引发NetworkOnMainThreadException:

E/SearchActivity: showSearchError: null
                  android.os.NetworkOnMainThreadException
                      at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1303)
                      at java.net.Inet6AddressImpl.lookupHostByName(Inet6AddressImpl.java:86)
                      at java.net.Inet6AddressImpl.lookupAllHostAddr(Inet6AddressImpl.java:74)
                      at java.net.InetAddress.getAllByName(InetAddress.java:752)
                      at okhttp3.Dns$1.lookup(Dns.java:39)
                      at okhttp3.internal.connection.RouteSelector.resetNextInetSocketAddress(RouteSelector.java:171)
                      at okhttp3.internal.connection.RouteSelector.nextProxy(RouteSelector.java:137)
                      at okhttp3.internal.connection.RouteSelector.next(RouteSelector.java:82)
                      at okhttp3.internal.connection.StreamAllocation.findConnection(StreamAllocation.java:171)
                      at okhttp3.internal.connection.StreamAllocation.findHealthyConnection(StreamAllocation.java:121)
                      at okhttp3.internal.connection.StreamAllocation.newStream(StreamAllocation.java:100)
                      at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:42)
                      at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
                      at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
                      at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93)
                      at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
                      at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
                      at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
                      at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
                      at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:120)
                      at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
                      at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
                      at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:185)
                      at okhttp3.RealCall.execute(RealCall.java:69)
                      at retrofit2.OkHttpCall.execute(OkHttpCall.java:180)
                      at retrofit2.adapter.rxjava2.CallExecuteObservable.subscribeActual(CallExecuteObservable.java:41)
                      at io.reactivex.Observable.subscribe(Observable.java:10910)
                      at retrofit2.adapter.rxjava2.BodyObservable.subscribeActual(BodyObservable.java:34)
                      at io.reactivex.Observable.subscribe(Observable.java:10910)
                      at io.reactivex.internal.operators.flowable.FlowableFromObservable.subscribeActual(FlowableFromObservable.java:29)
                      at io.reactivex.Flowable.subscribe(Flowable.java:12994)
                      at io.reactivex.internal.operators.flowable.FlowableOnBackpressureLatest.subscribeActual(FlowableOnBackpressureLatest.java:32)
                      at io.reactivex.Flowable.subscribe(Flowable.java:12994)
                      at io.reactivex.internal.operators.flowable.FlowableMap.subscribeActual(FlowableMap.java:38)
                      at io.reactivex.Flowable.subscribe(Flowable.java:12994)
                      at io.reactivex.internal.operators.flowable.FlowablePublish.connect(FlowablePublish.java:130)
                      at io.reactivex.flowables.ConnectableFlowable.connect(ConnectableFlowable.java:64)
                      at com.github.alexpfx.udacity.beercollection.beer.search.DefaultSearchPresenter.search(DefaultSearchPresenter.java:50)
                      at com.github.alexpfx.udacity.beercollection.SearchActivity.actionSearch(SearchActivity.java:63)
                      at com.github.alexpfx.udacity.beercollection.SearchActivity_ViewBinding$1.doClick(SearchActivity_ViewBinding.java:35)
                      at butterknife.internal.DebouncingOnClickListener.onClick(DebouncingOnClickListener.java:22)
                      at android.view.View.performClick(View.java:6261)
                      at android.view.View$PerformClick.run(View.java:23748)
                      at android.os.Handler.handleCallback(Handler.java:751)
                      at android.os.Handler.dispatchMessage(Handler.java:95)
                      at android.os.Looper.loop(Looper.java:154)
                      at android.app.ActivityThread.main(ActivityThread.java:6776)
                      at java.lang.reflect.Method.invoke(Native Method)
                      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1496)
                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1386)

我没有意识到出了什么问题,因为订阅不是在主线程中执行的。

- 我的SchedulerProvider类:

@Singleton
public class AndroidSchedulerProvider implements SchedulerProvider {

    @Inject
    public AndroidSchedulerProvider() {
    }

    @Override
    public Scheduler computation() {
        return Schedulers.computation();
    }

    @Override
    public Scheduler io() {
        return Schedulers.io();
    }

    @Override
    public Scheduler ui() {
        return AndroidSchedulers.mainThread();
    }
}

1 个答案:

答案 0 :(得分:2)

你应该在.subscribeOn(schedulerProvider.io()) }之前放置publish() ,这样底层的service.searchBeers Flowable会订阅io线程,当你放入subscribeOn在发布后,它将仅影响ConnectableFlowable本身的订阅。

service.searchBeers(config.getKey(), name)
            .map(Mappers.SEARCH_MAPPER)
            .subscribeOn(schedulerProvider.io())
            .publish();