ReactiveLocationProvider with RetroFit2 in Android throwing NetworkOnMainThread

329 Views Asked by At

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)
2

There are 2 best solutions below

0
On

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

4
On

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());