Create a sync adapter

Note: We recommended WorkManager
as the recommended solution for most background processing use cases. Please reference the
background processing guide to learn which solution works best for you.

The sync adapter component in your app encapsulates the code for the tasks that transfer
data between the device and a server. Based on the scheduling and triggers you provide in
your app, the sync adapter framework runs the code in the sync adapter component. To add a
sync adapter component to your app, you need to add the following pieces:

Sync adapter class.

A class that wraps your data transfer code in an interface compatible with the sync adapter
framework.

A component that allows the sync adapter framework to run the code in your sync adapter
class.

Sync adapter XML metadata file.

A file containing information about your sync adapter. The framework reads this file to
find out how to load and schedule your data transfer.

Declarations in the app manifest.

XML that declares the bound service and points to sync adapter-specific metadata.

This lesson shows you how to define these elements.

Create a sync adapter class

In this part of the lesson you learn how to create the sync adapter class that encapsulates the
data transfer code. Creating the class includes extending the sync adapter base class, defining
constructors for the class, and implementing the method where you define the data transfer
tasks.

Extend the base sync adapter class

To create the sync adapter component, start by extending
AbstractThreadedSyncAdapter and writing its constructors. Use the
constructors to run setup tasks each time your sync adapter component is created from
scratch, just as you use Activity.onCreate() to set up an
activity. For example, if your app uses a content provider to store data, use the constructors
to get a ContentResolver instance. Since a second form of the
constructor was added in Android platform version 3.0 to support the parallelSyncs
argument, you need to create two forms of the constructor to maintain compatibility.

Note: The sync adapter framework is designed to work with sync adapter
components that are singleton instances. Instantiating the sync adapter component is covered
in more detail in the section
Bind the Sync Adapter to the Framework.

Add the data transfer code

The sync adapter component does not automatically do data transfer. Instead, it
encapsulates your data transfer code, so that the sync adapter framework can run the
data transfer in the background, without involvement from your app. When the framework is ready
to sync your application's data, it invokes your implementation of the method
onPerformSync().

To facilitate the transfer of data from your main app code to the sync adapter component,
the sync adapter framework calls
onPerformSync() with the
following arguments:

Account

An Account object associated with the event that triggered
the sync adapter. If your server doesn't use accounts, you don't need to use the
information in this object.

Extras

A Bundle containing flags sent by the event that triggered the sync
adapter.

Authority

The authority of a content provider in the system. Your app has to have access to
this provider. Usually, the authority corresponds to a content provider in your own app.

Content provider client

A ContentProviderClient for the content provider pointed to by the
authority argument. A ContentProviderClient is a lightweight public
interface to a content provider. It has the same basic functionality as a
ContentResolver. If you're using a content provider to store data
for your app, you can connect to the provider with this object. Otherwise, you can ignore
it.

Sync result

A SyncResult object that you use to send information to the sync
adapter framework.

While the actual implementation of
onPerformSync() is specific to
your app's data synchronization requirements and server connection protocols, there are a few
general tasks your implementation should perform:

Connecting to a server

Although you can assume that the network is available when your data transfer starts, the
sync adapter framework doesn't automatically connect to a server.

Downloading and uploading data

A sync adapter doesn't automate any data transfer tasks. If you want to download
data from a server and store it in a content provider, you have to provide the code that
requests the data, downloads it, and inserts it in the provider. Similarly, if you want to
send data to a server, you have to read it from a file, database, or provider, and send
the necessary upload request. You also have to handle network errors that occur while your
data transfer is running.

Handling data conflicts or determining how current the data is

A sync adapter doesn't automatically handle conflicts between data on the server and data
on the device. Also, it doesn't automatically detect if the data on the server is newer than
the data on the device, or vice versa. Instead, you have to provide your own algorithms for
handling this situation.

Clean up.

Always close connections to a server and clean up temp files and caches at the end of
your data transfer.

Note: The sync adapter framework runs
onPerformSync() on a
background thread, so you don't have to set up your own background processing.

In addition to your sync-related tasks, you should try to combine your regular
network-related tasks and add them to
onPerformSync().
By concentrating all of your network tasks in this method, you conserve the battery power that's
needed to start and stop the network interfaces. To learn more about making network access more
efficient, see the training class Transferring Data Without Draining the Battery, which describes several network access
tasks you can include in your data transfer code.

Bind the sync adapter to the framework

You now have your data transfer code encapsulated in a sync adapter component, but you have
to provide the framework with access to your code. To do this, you need to create a bound
Service that passes a special Android binder object from the sync adapter
component to the framework. With this binder object, the framework can invoke the
onPerformSync() method and
pass data to it.

Instantiate your sync adapter component as a singleton in the
onCreate() method of the service. By instantiating
the component in onCreate(), you defer
creating it until the service starts, which happens when the framework first tries to run your
data transfer. You need to instantiate the component in a thread-safe manner, in case the sync
adapter framework queues up multiple executions of your sync adapter in response to triggers or
scheduling.

For example, the following snippet shows you how to create a class that implements the
bound Service, instantiates your sync adapter component, and gets the
Android binder object:

Note: To see a more detailed example of a bound service for a sync adapter,
see the sample app.

Add the account required by the framework

The sync adapter framework requires each sync adapter to have an account type. You declared
the account type value in the section
Add the Authenticator Metadata File. Now you have to set up this account type in the
Android system. To set up the account type, add a dummy account that uses the account type
by calling addAccountExplicitly().

The best place to call the method is in the
onCreate() method of your app's
opening activity. The following code snippet shows you how to do this:

Add the sync adapter metadata file

To plug your sync adapter component into the framework, you need to provide the framework
with metadata that describes the component and provides additional flags. The metadata specifies
the account type you've created for your sync adapter, declares a content provider authority
associated with your app, controls a part of the system user interface related to sync adapters,
and declares other sync-related flags. Declare this metadata in a special XML file stored in
the /res/xml/ directory in your app project. You can give any name to the file,
although it's usually called syncadapter.xml.

This XML file contains a single XML element <sync-adapter> that has the
following attributes:

android:contentAuthority

The URI authority for your content provider. If you created a stub content provider for
your app in the previous lesson Creating a Stub Content Provider, use the value you specified for the
attribute
android:authorities
in the <provider> element you added to your app manifest. This attribute is
described in more detail in the section
Declare the Provider in the Manifest.
If you're transferring data from a content provider to a server with your sync adapter, this
value should be the same as the content URI authority you're using for that data. This value
is also one of the authorities you specify in the
android:authorities
attribute of the <provider> element that declares your provider in your app manifest.

Sets the visibility of the sync adapter's account type. By default, the
account icon and label associated with the account type are visible in the
Accounts section of the system's Settings app, so you should make your sync
adapter invisible unless you have an account type or domain that's easily associated
with your app. If you make your account type invisible, you can still allow users to
control your sync adapter with a user interface in one of your app's activities.

android:supportsUploading

Allows you to upload data to the cloud. Set this to false if your app only
downloads data.

android:allowParallelSyncs

Allows multiple instances of your sync adapter component to run at the same time.
Use this if your app supports multiple user accounts and you want to allow multiple
users to transfer data in parallel. This flag has no effect if you never run
multiple data transfers.

android:isAlwaysSyncable

Indicates to the sync adapter framework that it can run your sync adapter at any
time you've specified. If you want to programmatically control when your sync
adapter can run, set this flag to false, and then call
requestSync() to run the
sync adapter. To learn more about running a sync adapter, see the lesson
Running a Sync Adapter

The following example shows the XML for a sync adapter that uses a single dummy account and
only does downloads.

Declare the sync adapter in the manifest

Once you've added the sync adapter component to your app, you have to request permissions
related to using the component, and you have to declare the bound Service
you've added.

Since the sync adapter component runs code that transfers data between the network and the
device, you need to request permission to access the Internet. In addition, your app needs
to request permission to read and write sync adapter settings, so you can control the sync
adapter programmatically from other components in your app. You also need to request a
special permission that allows your app to use the authenticator component you created
in the lesson Creating a Stub Authenticator.

To request these permissions, add the following to your app manifest as child elements of
<manifest>:

Allows the sync adapter code to access the Internet so that it can download or upload data
from the device to a server. You don't need to add this permission again if you were
requesting it previously.

Allows your app to control sync adapter settings. You need this permission in order to
set periodic sync adapter runs using addPeriodicSync(). This permission is not required to call
requestSync(). To learn more about
running the sync adapter, see Running A Sync Adapter.

The
<intent-filter>
element sets up a filter that's triggered by the intent action
android.content.SyncAdapter, sent by the system to run the sync adapter. When the filter
is triggered, the system starts the bound service you've created, which in this example is
SyncService. The attribute
android:exported="true"
allows processes other than your app (including the system) to access the
Service. The attribute
android:process=":sync"
tells the system to run the Service in a global shared process named
sync. If you have multiple sync adapters in your app they can share this process,
which reduces overhead.

The
<meta-data>
element provides provides the name of the sync adapter metadata XML file you created previously.
The
android:name
attribute indicates that this metadata is for the sync adapter framework. The
android:resource
element specifies the name of the metadata file.

You now have all of the components for your sync adapter. The next lesson shows you how to
tell the sync adapter framework to run your sync adapter, either in response to an event or on
a regular schedule.