I observed this behavior as well.
It is correct, that addAccountExplicit() will trigger a system-wide account resync of stale accounts.
Clarificiation
However, Zapek's observation about addPeriodic sync or request sync being "immediate" syncs, is not quite correct. Both are just queued. Additionally the following holds for addPeriodicSync():
These periodic syncs honor the "syncAutomatically" and
"masterSyncAutomatically" settings. Although these sync are scheduled
at the specified frequency, it may take longer for it to actually be
started if other syncs are ahead of it in the sync operation queue.
This means that the actual start time may drift.
(Documentation)
Pertaining to your problem
What you experience is described in the training on running sync adapters:
The method addPeriodicSync() doesn't disable setSyncAutomatically(),
so you may get multiple sync runs in a relatively short period of
time. Also, only a few sync adapter control flags are allowed in a
call to addPeriodicSync(); the flags that are not allowed are
described in the referenced documentation for addPeriodicSync().
Android Training Sync Adapter
Google's own solution looks like yours, with a lower frequency even (60*60=3600):
if (accountManager.addAccountExplicitly(account, null, null)) {
// Inform the system that this account supports sync
ContentResolver.setIsSyncable(account, CONTENT_AUTHORITY, 1);
// Inform the system that this account is eligible for auto sync when the network is up
ContentResolver.setSyncAutomatically(account, CONTENT_AUTHORITY, true);
// Recommend a schedule for automatic synchronization. The system may modify this based
// on other scheduled syncs and network utilization.
ContentResolver.addPeriodicSync(
account, CONTENT_AUTHORITY, new Bundle(),SYNC_FREQUENCY);
newAccount = true;
}
Proposition
I propose using the SyncStats in onPerformSync() to actually return some information about your initial sync to the system, so it can schedule more efficiently.
syncResult.stats.numEntries++; // For every dataset
this may not help if the other task is already scheduled - investigating
Additionally one may set up a flag 'isInitialOnPerformSync' (w. sharedPreferences), to cause other tasks to back up.
syncResult.delayUntil = <time>;
I personally am not really fan of creating a fixed no sync timeframe after the initial sync.
Further Considerations - Initial Sync Immediately
As stated in the clarification, the sync will not run immediately with your settings. There is a solution, that will let you sync immediately. This will not influence the sync settings, and will not cause them to backoff, which is why this does not solve your problem, but it has the effect that your user will not have to wait for sync to kick in. Important if you use this to display the main content in your app this way.
Code:
Set up a flag for isInitialSync inside your normal app process (which you save e.g. in defaultSharedPreferences). You can even use the Upon the initial completion of the installation or login (if authentication is required) you can invoke an immediate sync as follow.
/**
* Start an asynchronous sync operation immediately. </br>
*
* @param account
*/
public static void requestSyncImmediately(Account account) {
// Disable sync backoff and ignore sync preferences. In other words...perform sync NOW!
Bundle settingsBundle = new Bundle();
settingsBundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
settingsBundle.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
// Request sync with settings
ContentResolver.requestSync(account, SyncConstants.CONTENT_AUTHORITY, settingsBundle);
}