1

I am facing android.os.NetworkOnMainThreadException while combining multiple observables using zip operator. I am using proper Schedulers as far as I know.

public void loadFeeds(final String... urls) {
    final List<Observable<Response>> observables = new ArrayList<>();
    for (String url : urls) {
        try {
            observables.add(Observable.just(RssParser.parse(url)));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    Observable<List<RSS>> rssListObservable = Observable.zip(observables, new Function<Object[], List<RSS>>() {
        public List<RSS> apply(Object[] objects) throws Exception {
            final List<RSS> rssList = new ArrayList<RSS>();

            for (Object object : objects) {
                Response response = (Response) object;
                RSS rss = new Persister().read(RSS.class, response.body().string());
                rssList.add(rss);
            }
            return rssList;
        }
    })
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread());

    disposable = rssListObservable.subscribeWith(new DisposableObserver<List<RSS>>() {
        @Override
        public void onNext(List<RSS> rssList) {
            //rssCallback.rssFeedsLoaded(rssList);
            Log.d(TAG, "onNext: rssListSize: "+rssList.size());
        }

        @Override
        public void onError(Throwable e) {
            Log.e(TAG, "onError: " + e.getMessage(), e);
        }

        @Override
        public void onComplete() {
            Log.d(TAG, "onComplete: done");
        }
    });
}

I am converting this method into observable using Observable.just()

static Response parse(String feedUrl) throws IOException {
    Request request = new Request.Builder()
            .url(feedUrl)
            .get()
            .build();

    return OK_HTTP_CLIENT.newCall(request).execute();
}

Here is the error log:

FATAL EXCEPTION: main
Process: com.crazyhitty.chdev.ks.rssmanagerlib, PID: 18980
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:170)
    at okhttp3.internal.connection.RouteSelector.nextProxy(RouteSelector.java:136)
    at okhttp3.internal.connection.RouteSelector.next(RouteSelector.java:81)
    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:179)
    at okhttp3.RealCall.execute(RealCall.java:63)
    at com.crazyhitty.chdev.ks.rssmanager.RssParser.parse(RssParser.java:29)
    at com.crazyhitty.chdev.ks.rssmanager.RssReader.loadFeeds(RssReader.java:43)
    at com.crazyhitty.chdev.ks.rssmanagerlib.MainActivity.loadFeeds(MainActivity.java:72)
    at com.crazyhitty.chdev.ks.rssmanagerlib.MainActivity.access$200(MainActivity.java:21)
    at com.crazyhitty.chdev.ks.rssmanagerlib.MainActivity$1.onClick(MainActivity.java:54)
    at android.view.View.performClick(View.java:5637)
    at android.view.View$PerformClick.run(View.java:22429)
    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:6119)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)

Any sort of help or guidance would be appreciated, thanks :)

Edit: Found the solution guys, basically as an RxJava newbie, I didn't know that Observable.just() instantly executes the observable on the current thread. So, instead of using Observable.just(), Observable.create() should be used in such scenario.

Fixed code:

public void loadFeeds(final String... urls) {
    final long startTimeMillis=System.currentTimeMillis();

    final List<Observable<RSS>> observables = new ArrayList<>();
    for (final String url : urls) {
        observables.add(Observable.create(new ObservableOnSubscribe<RSS>() {
            @Override
            public void subscribe(ObservableEmitter<RSS> emitter) throws Exception {
                RSS rss = new Persister().read(RSS.class, RssParser.parse(url).body().string());
                Log.d(TAG, "subscribe: url: " + url + " ; thread: " + Thread.currentThread().getName());
                emitter.onNext(rss);
                emitter.onComplete();
            }
        }));
    }

    Observable<List<RSS>> rssListObservable = Observable.zip(observables, new Function<Object[], List<RSS>>() {
        @Override
        public List<RSS> apply(Object[] objects) throws Exception {
            final List<RSS> rssList = new ArrayList<RSS>();

            for (Object object : objects) {
                rssList.add((RSS) object);
            }

            return rssList;
        }
    }).subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread());

    disposable = rssListObservable.subscribeWith(new DisposableObserver<List<RSS>>() {
        @Override
        public void onNext(List<RSS> rssList) {
            rssCallback.rssFeedsLoaded(rssList);
            Log.d(TAG, "onNext: rssListSize: " + rssList.size());
        }

        @Override
        public void onError(Throwable e) {
            rssCallback.unableToReadRssFeeds(e.getMessage());
            Log.e(TAG, "onError: " + e.getMessage(), e);
        }

        @Override
        public void onComplete() {
            Log.d(TAG, String.format(Locale.ENGLISH, "onComplete: done with time spent(ms): %d", (System.currentTimeMillis()-startTimeMillis)));
        }
    });
}
  • Dear 2Dee, would you please give us simple google search terms that will answer this question. Btw I think this question is incorrectly marked as duplicate. – Okas Feb 27 '17 at 16:27
  • Yup, this question was incorrectly marked as a duplicate due to NetworkOnMainThreadException. Still, I got the solution for this problem somehow. @2Dee Ouch, looks like someone had a bad day today. – Kartik Sharma Feb 27 '17 at 16:43
  • I am not using just operator still getting NetworkOnMainThreadException. – karthik kolanji Jun 13 '17 at 09:14

0 Answers0