vendredi 17 juin 2016

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.

Aucun commentaire:

Enregistrer un commentaire