Search code examples
androidandroid-syncadapter

How to schedule synchronization for Internet connectivity only


I'm using a Sync Adapter to perform synchronization for my app. It has set automatic sync:

// Inform the system that this account supports sync
ContentResolver.setIsSyncable(account, AuthenticatorService.AUTHORITY, 1);
// Inform the system that this account is eligible for auto sync when the network is up
ContentResolver.setSyncAutomatically(account, AuthenticatorService.AUTHORITY, true);

If I request the sync:

Bundle b = new Bundle();
// Disable sync backoff and ignore sync preferences. In other words...perform sync NOW!
b.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
b.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
ContentResolver.requestSync(AuthenticatorService.GetAccount(), AuthenticatorService.AUTHORITY, b);

it works well -- as soon as the network is up, SyncAdapter.onPerformSync() is called. However, there's one problem: if the network is up but not connected to Internet (hotspot without tethering for instance), onPerformSync() is still called.

Of course, since it can't reach the server, sync code fails. What is worse, the system thinks everything went OK and wont do any more sync calls unless my data change.

My question is: can I either mark the synchronization as not successful so the system will try it later (for instance on another CONNECTED event or in a few seconds) or better to tell the system to perform the sync only when real Internet connectivity is present?

I could monitor the network state and do a connectivity check by myself but that would defy the whole purpose of sync adapters, wouldn't it. Only workaround I can think of is to schedule periodic synchronization (using ContentResolver.addPeriodicSync()) and when my synchronization code succeeds, turn it off. But I'm not very happy about this either (draining battery).

EDIT: As for the first part of my question, this answer is what I was looking for. It partially solves my problem but if there's consecutive number of "non-working" connections, when the device is associated with the real connection, it would take tens of minutes to sync (because of the exponential backoff algorithm).


Solution

  • Thanks to csenga's suggestion I found a solution: use GcmNetworkManager to schedule the synchronization. It looks a bit stupid as I have to declare yet another service just to call ContentResolver.requestSync() and if something goes wrong I have to reschedule my task instead of setting the SyncResult.stat flags (I'm virtually duplicating Sync Adapter's job here) but still better than to handle my own NETWORK_STATE_CHANGED_ACTION receiver.