Lukasz
Lukasz

Reputation: 2317

RxAndroid - Error in http connectionandroid.os.NetworkOnMainThreadException

I have the following peace of code containing network operations. Where I get the well known error Error in http connectionandroid.os.NetworkOnMainThreadException which is pretty descriptive and explained for example here.

What I don't understand is, how can the error occur here when I clearly subscribe on Scheduler.io(). What do I do wrong?

ReactiveLocationProvider locationProvider = new ReactiveLocationProvider(mContext);
locationProvider.getLastKnownLocation().subscribeOn(Schedulers.io()).subscribe((location -> {
    // ... unrelated code
    try {
        this.postPing(pingResponse); // <<< this is an http post causing the error
        Log.d(LOG_TAG, "trying to post response");
    } catch (Exception e) {
        e.printStackTrace();
    }
    cursor.close();

Edit: This does not seem to be entirely trivial. That's why I provide additional context.

The code above used to look like this and didn't use ReactiveLocationProvider, but rather the FusedLocationApi

 Location location = LocationServices.FusedLocationApi.getLastLocation(MainActivity.mGoogleApiClient);
                    // ... unrelated code
                    try {
                        this.postPing(pingResponse);
                        Log.d(LOG_TAG, "trying to post response");
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    cursor.close();

And was run from within a GcmListenerService:

@Override
    public void onMessageReceived(String from, Bundle data) {
        Log.d("GCMListener", "onMessageReceived");
        String action = data.getString("action");
        switch (action) {
            case "getPing":
                requests.getPingObservable()
                        .subscribeOn(Schedulers.io()).retryWhen(
                        errors ->
                                errors
                                        .zipWith(Observable.range(1, 3), (n, i) -> i)
                                        .flatMap(retryCount -> Observable.timer((long) Math.pow(5, retryCount), TimeUnit.SECONDS))
                        ).subscribe((pingsJsonObjectString) -> {
                }, (error) -> error.printStackTrace());
                break;
            default:
                break;
        }
    }

Unfortunately the GcmListenerService doesn't receive notifications when the app is closed. So I decided to cheat a bit and create an alarm to trigger the reciever with an alarm.

In The AndroidMainfest.xml I added the line <category android:name="com.smilingkoala.ping.periodic_wakeup"/>

<!-- The Google Cloud Messaging receiver and services -->
        <receiver
            android:name="com.google.android.gms.gcm.GcmReceiver"
            android:exported="true"
            android:permission="com.google.android.c2dm.permission.SEND">
            <intent-filter>
                <action android:name="com.google.android.c2dm.intent.RECEIVE" />
                <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
                <category android:name="com.smilingkoala.ping" />
                <category android:name="com.smilingkoala.ping.periodic_wakeup"/>
            </intent-filter>
        </receiver>

and in MainActivity.java I called:

public void startAlarm(Context context) {
    Intent intent = new Intent("com.smilingkoala.ping.periodic_wakeup");
    PendingIntent sender = PendingIntent.getService(context, 0, intent, 0);
    AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
    am.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
            AlarmManager.INTERVAL_FIFTEEN_MINUTES / 3, AlarmManager.INTERVAL_FIFTEEN_MINUTES, sender);
}

To restart the listener once the application is closed. This actually worked. I received a message. But now I didn't have access to MainActivity.mGoogleApiClient which I used in the old code. That's why I was forced to use ReactiveLocationProvider. However now i can't run the networking code.

I assume something I did leading up to this Error is forbidden.

Upvotes: 1

Views: 179

Answers (1)

aleien
aleien

Reputation: 821

Ok, I am not 100% sure, but let's try to explain this (:

If you read documentation on .subscribeOn operator, you'll see that it defines scheduler on which Observable itself (not the Subscriber!) will be executed. You need to explicitly define scheduler for subscriber with .observeOn operator, or it will be executed on thread where it was subscribed on.

For more detailed information and examples you should check these links: http://www.grahamlea.com/2014/07/rxjava-threading-examples/ http://www.introtorx.com/Content/v1.0.10621.0/15_SchedulingAndThreading.html#SubscribeOnObserveOn

Also you can debug and experiment with threading by calling Thread.currentThread() to check where is your code executing.

Upvotes: 2

Related Questions