Android SyncAdapter Automatically Initialize Syncing
Solution 1
ContentResolver.setIsSyncable(account, AUTHORITY, 1);
ContentResolver.setSyncAutomatically(account, AUTHORITY, true);
As Blehi said will initiate the automatic syncing of the given account, given the global Settings, "Background data" and "Auto-sync" are enabled.
To prevent the back-to-back syncing (from jcwenger) make sure that if any method in the
SyncAdapter.onPerformSync(...)
calls ContentResolver.notifyChange(...)
it uses ContentResolver.notifyChange(uri, observer, false)
to flag the notify not to trigger a sync call (the third parameter is syncToNetwork
).
If you're using the ContentProvider
to perform the inserts/deletes/updates for you SyncAdapter
it makes sense to call ContentResolver.notifyChange(...)
so that while the app is visible the user can receive updates from the SyncAdapter
, which means you will have the ContentProvider
making ContentResolver.notifyChange(...)
calls. To get this set up to work, I've added (following the dev guide) CALLER_IS_SYNC_ADAPTER
query parameter to every URI that is used for the SyncAdapter
. Add this method to the ContentProvider
to test the incoming URIs
/**
* Determines if the given URI specifies that the request is coming from the sync adapter.
* @param uri the given URI
* @return true if the uri specifies that the request is coming from the sync adapter
*/
private boolean callerIsSyncAdapter(Uri uri) {
final String is_sync_adapter = uri.getQueryParameter(CALLER_IS_SYNC_ADAPTER);
return is_sync_adapter != null && !is_sync_adapter.equals("0");
}
then you can do
getContext().getContentResolver().notifyChange(uri, observer, !callerIsSyncAdapter(uri));
whenever you need send a change notification.
And if you want to schedule the sync to be executed periodically at a frequency (polling the server) add this with the ContentResolver.setSyncAutomatically(...)
call.
ContentResolver.addPeriodicSync(account, AUTHORITY, new Bundle(), frequency_in_seconds)
Solution 2
Just to emphasise, it seems that addPeriodicSync() needs setSyncAutomatically(), even though the documentation says that setSyncAutomatically() is only for detecting network tickles.
Note that the period will be corrected to >60s if it's less than a minute.
Solution 3
You have to set the account to be syncable by default:
ContentResolver.setIsSyncable(account, AUTHORITY, 1);
ContentResolver.setSyncAutomatically(account, AUTHORITY, true);
I use the above 2 lines and it is working properly.
Solution 4
Initially create an account and check the sync support for the same using AccountManager. If the account supports sync then call setIsSyncable() and setSyncAutomatically().
AccountManager accountManager = (AccountManager) this.getSystemService(ACCOUNT_SERVICE);
if(accountManager.addAccountExplicitly(newAccount, null, null)){
ContentResolver.setIsSyncable(account, AUTHORITY, 1);
ContentResolver.setSyncAutomatically(account, AUTHORITY, true);
}
Then you can trigger sync anytime. It will trigger.
Note: onPerformSync() of setSyncAutomatically() will be called first then only other sync request will be triggered. But to make force sync just add 2 extra flags.
Bundle bundle= new Bundle();
bundle.putBoolean(
ContentResolver.SYNC_EXTRAS_MANUAL, true);
bundle.putBoolean(
ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
ContentResolver.requestSync(account, AUTHORITY, bundle);
Dandre Allison
Medium: @dandre.allison Twitter: @imminenttweet Instagram: @imminentdomain
Updated on July 03, 2022Comments
-
Dandre Allison almost 2 years
I have a
SyncAdapter
for my app, and anAccountManager
to add my apps accounts to the Android Account Manager. My code for when I add an account to the Account Manager looks like:Bundle data = new Bundle(5); data.putString(_PEOPLE_ID, people_id); data.putString(_FIRST_NAME, first_name); data.putString(_LAST_NAME, last_name); data.putString(_PLAN, plan); data.putString(_BIRTHDAY, birthday); Account account = new Account(username, _ACCOUNT_TYPE); try { boolean created; created = _account_manager.addAccountExplicitly(account, _cryptography.encrypt(_SEED, password), data); response.accountCreated(created); _account_manager.setAuthToken(account, _TOKEN_TYPE, session_token); _model.updateActiveAccount(people_id, username, password); SharedPreferences.Editor settings = _settings.edit(); settings.putString(_ACCOUNT_TYPE, account.name); settings.putString(_TOKEN_TYPE, session_token); settings.commit(); // Tells the content provider that it can sync this account ContentResolver.setIsSyncable(account, AUTHORITY, 1); final Bundle extras = new Bundle(1); extras.putBoolean(SYNC_EXTRAS_INITIALIZE, true); ContentResolver.addPeriodicSync(account, AUTHORITY, extras, 900); } catch (Exception e) { Ln.e(e.getCause()); }
I can add the account to the Account Manager successfully through Settings, but I have to manually enable syncing for the account in Settings also, even though background data and sync automatically settings are enabled on the emulator. If I manually enable syncing, then the sync is performed fine, it just isn't started by default.
-
Dandre Allison almost 12 yearsAdding ContentResolver.setSyncAutomatically(account, AUTHORITY, true); is what I needed, but it seems that it isn't acknowledging the periodic sync. After I add an account it just keeps syncing repeatedly.
-
Blehi almost 12 yearsPlease try to call the ContentResolver.addPeriodicSync() function with new Bundle() instead of extras.
-
Dandre Allison almost 12 yearsextras is a new Bundle(), I'm even trying it without attempting to set any of the flags (Bundle extras = new Bundle(); addPeriodicSync(account, AUTHORITY, extras, 900);)
-
kapeels over 10 yearsThis is quite late, but what is
AUTHORITY
here? -
kapeels over 10 yearsI just figured out it's the string you have in the
android:contentAuthority
attribute in yoursync-adapter
tag.