2

The code below consistently throws a NetworkOnMainThread on Android, call attempt is to get a location and use it to fetch a list via a RetroFit 2 API, which works fine in other circumstances, as does the ReactiveLocation call.

new ReactiveLocationProvider(this).getLastKnownLocation()
  .singleOrDefault(null)
  .flatMap(new Func1<Location, Observable<List<OfferLocation>>>() {
    @Override
    public Observable<List<OfferLocation>> call(Location location) {
      return ARetrofitAPI.getOfferLocations(offer.getId(), latLng);
    }
  })
  .subscribeOn(Schedulers.io())
  .observeOn(AndroidSchedulers.mainThread())
  .subscribe();

getLastKnownLocation() works fine and then the RetroFit wrapper call, that works EVERYWHERE else, throws NetworkOnMainThreadException, I've tried both 0.9 and 0.10, when either are by themselves in separate subscriptions all is fine.

The expected result would be for the result of the flatMap() to run on the io() Scheduler NOT on the mainThread().

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:172)
    at okhttp3.internal.connection.RouteSelector.nextProxy(RouteSelector.java:138)
    at okhttp3.internal.connection.RouteSelector.next(RouteSelector.java:80)
    at okhttp3.internal.connection.StreamAllocation.findConnection(StreamAllocation.java:178)
    at okhttp3.internal.connection.StreamAllocation.findHealthyConnection(StreamAllocation.java:129)
    at okhttp3.internal.connection.StreamAllocation.newStream(StreamAllocation.java:98)
    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:109)
    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:124)
    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
    at okhttp3.logging.HttpLoggingInterceptor.intercept(HttpLoggingInterceptor.java:212)
    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
    at com.greenlight.zubie.network.ZubieRetrofit$ZubieCallInterceptor.intercept(ZubieRetrofit.java:1063)
    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
    at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:170)
    at okhttp3.RealCall.execute(RealCall.java:60)
    at retrofit2.OkHttpCall.execute(OkHttpCall.java:174)
    at retrofit2.adapter.rxjava.RxJavaCallAdapterFactory$RequestArbiter.request(RxJavaCallAdapterFactory.java:171)
    at rx.Subscriber.setProducer(Subscriber.java:211)
    at rx.internal.operators.OperatorMap$MapSubscriber.setProducer(OperatorMap.java:99)
    at rx.internal.operators.OperatorMap$MapSubscriber.setProducer(OperatorMap.java:99)
    at retrofit2.adapter.rxjava.RxJavaCallAdapterFactory$CallOnSubscribe.call(RxJavaCallAdapterFactory.java:152)
    at retrofit2.adapter.rxjava.RxJavaCallAdapterFactory$CallOnSubscribe.call(RxJavaCallAdapterFactory.java:138)
    at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:50)
    at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30)
    at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:50)
    at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30)
    at rx.Observable.unsafeSubscribe(Observable.java:8666)
    at rx.internal.operators.OperatorMerge$MergeSubscriber.onNext(OperatorMerge.java:250)
    at rx.internal.operators.OperatorMerge$MergeSubscriber.onNext(OperatorMerge.java:147)
    at rx.internal.operators.OperatorMap$MapSubscriber.onNext(OperatorMap.java:74)
    at rx.internal.operators.OperatorObserveOn$ObserveOnSubscriber.call(OperatorObserveOn.java:227)
    at rx.android.schedulers.LooperScheduler$ScheduledAction.run(LooperScheduler.java:107)
    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:6077)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
Kenny
  • 805
  • 8
  • 19

2 Answers2

1

I'm not sure but is this the problem?

By default, all network calls are synchronous:

RxJavaCallAdapterFactory rxAdapter = RxJavaCallAdapterFactory.create();

If you wish to default network calls to be asynchronous, you need to use createWithScheduler().

RxJavaCallAdapterFactory rxAdapter = RxJavaCallAdapterFactory.createWithScheduler(Schedulers.io());

nasch
  • 5,330
  • 6
  • 31
  • 52
  • I'm not seeing why you have the question? Granted the code snippet is simplified, but it specifically is scheduling with Schedulers.io(), but the flatmap() function following the request for location is running on the mainthread, I would expect the flatmap to run within the scheduler not on the observer as it is returning a second Observable. – Kenny Sep 28 '16 at 13:49
  • @Kenny Did you mean to put this comment on the question, or my answer? – nasch Sep 28 '16 at 15:04
  • It was intended here, where I'm confused is why aren't both observables, both the getLastKnownLocation AND the result of the flatMap, subscribed on the io() scheduler? The only way I've been able to make the Retrofit call run in the io() scheduler and not on the mainThread() is by specifying the scheduleOn in the result of the flatMap. – Kenny Sep 28 '16 at 16:38
  • Oh I didn't notice you were the questioner, derp. I have no idea, I've never used Retrofit with RxJava. I just noticed that bit in the documentation and thought it might be related. – nasch Sep 28 '16 at 20:44
1

In my case I have added .observeOn(Schedulers.io()) after getLastKnownLocation() and it works

Endrju
  • 46
  • 1
  • 3