Sync Adapter in Android – A Simple Example…

By | July 6, 2015

Hello all,

In Today’s article we will be discussing about the SyncAdapters in Android.
SyncAdapter is just a simple plugin like structure for syncing your server and Device.

Check out this post about Account authenticator before proceeding.

Android Sync Adapter

Why do we use SyncAdapter instead of Using Alarm Manger to Sync?

Automated execution
    Sync can be requested based on variety of criteria, including data changes, elapsed time, or time of day.
Automated network checking
     The system only runs your data transfer when the device has network connectivity.
Improved battery performance
     Allows you to centralize all of your app’s data transfer tasks in one place, so that they all run at the same time. Your data transfer is also scheduled in conjunction with data transfers from other apps. These factors reduce the number of times the system has to switch on the network, which reduces battery usage.
Account management and authentication
     If your app requires user credentials or server login, you can optionally integrate account management and authentication into your data transfer.
Automatic Retry
     Failed syncs are retried with exponential backoffs.

What makes the Sync Adapter?

There are three components that makes up the SyncAdapter..

1.A Content-provider that extends ContentProvider.
2. An Adapter that extends AbstractThreadedSyncAdapter.
3. A Service that extends Service – this links the content provider with the sync adapter

The Content- provider and the Service need to be declared in AndroidManifest.xml.

For example the declaration will look like this…


   <provider
            android:name="MyContentProvider"
            android:authorities="@string/content_authority"
            android:exported="false"
            android:label="MyContentProvider"
            android:syncable="true" />
            
   <service
            android:name="AuthenticatorService"
            android:exported="true"
            android:process=":auth" >
            <intent-filter>
                <action android:name="android.accounts.AccountAuthenticator" />
            </intent-filter>

            <meta-data
                android:name="android.accounts.AccountAuthenticator"
                android:resource="@xml/authenticator" />
    </service>
    
	<service
		android:name="SyncService"
		android:exported="true"
		android:process=":sync" >
		<intent-filter>
			<action android:name="android.content.SyncAdapter" />
		</intent-filter>

		<meta-data
			android:name="android.content.SyncAdapter"
			android:resource="@xml/sync_adapter" />
	</service>

Now create a folder inside the “res” folder named “xml” and create two xmls, one for the autheticator and other for the Adapter.

authenticator.xml

<account-authenticator 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:accountType="@string/auth_type"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:smallIcon="@drawable/ic_launcher" />

sync_adapter.xml

<?xml version="1.0" encoding="utf-8"?>
<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
              android:contentAuthority="@string/content_authority"
              android:accountType="@string/auth_type"
              android:userVisible="true"
              android:allowParallelSyncs="true"
              android:isAlwaysSyncable="true"
              android:supportsUploading="false"/>

strings.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">Android Account Authenticator</string>
    <string name="hello_world">Hello world!</string>
    <string name="action_settings">Settings</string>
    <string name="auth_type">com.coderzheaven.auth_example</string>
    <string name="content_authority">com.coderzheaven.mycont_provider</string>
</resources>

NOTE : The “android:authorities” in the Provider Declaration and “android:contentAuthority” in the Sync Adapter should match.
That is why I put it in the strings.xml and gave a common name.

Authority is the string which establishes the relationship among the service, content provider and sync adapter.
In the above example “com.coderzheaven.mycont_provider”.

To Start Sync.

ContentResolver.requestSync(account, authority, bundle);  

The account should be valid.

For periodic Syncing.

ContentResolver.addPeriodicSync (account, authority, extras,frequency)

When you request Sync, the System may not start the Syncing immediately, because it will wait for the best battery performance.

Sync Immediately.

If we want to Sync immediately…

 Bundle bundle = new Bundle();  
 //Set below two flags
 bundle.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);  
 bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);  
 ContentResolver.requestSync(account, authority, bundle);  

NOTE : Periodic syncs are not allowed to have any of SYNC_EXTRAS_DO_NOT_RETRY, SYNC_EXTRAS_IGNORE_BACKOFF,
SYNC_EXTRAS_IGNORE_SETTINGS, SYNC_EXTRAS_INITIALIZE, SYNC_EXTRAS_FORCE,SYNC_EXTRAS_EXPEDITED, SYNC_EXTRAS_MANUAL set to true.
If any are supplied then an IllegalArgumentException will be thrown.

if we request an immediate sync when another sync is already in progress, then sync would be retried after 10 seconds.

NOTE : In Some devices Periodic Sync will not work unless “Auto-Sync” is turned on.

Full Source code that implements Android Authenticator and Sync Adapter is available here.

Please leave your valuable comments below.