How do I use the Android SyncAdapter?
I try to understand the Android synchronization logic. What I don't understand is the file syncadapter.xml
contained in the Android SDK sample project SampleSyncAdapter
. If you downloaded the SDK samples it should be in the following folder:
SDK/android-sdk-PLATFORM/samples/android-VERSION/SampleSyncAdapter/res/xml/syncadapter.xml
I read, the authority of a content provider should be a string or a reference to a resource. What exactly is the content authority and where is com.android.contacts
? Here is the content of the file (w/o license information and comments, API level 16).
<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
android:contentAuthority="com.android.contacts"
android:accountType="com.example.android.samplesync"
android:supportsUploading="false"
android:userVisible="true"
/>
Solution 1:
There are two basic methods you can use when making a SyncAdapter:
- Fill data into an existing ContentProvider.
- Create your own ContentProvider to store a new kind of data.
The former is what's going on in this example app. They have some website that has a list of contacts, and they want to store those along with the other contacts on the device. In either case, the way this all works is through a relationship between three components:
- A ContentProvider, which stores the data.
- A SyncAdapter, which communicates with a remote server to obtain data to put into the ContentProvider.
- The Android ContentResolver, which figures out how to pair up SyncAdapters and ContentProviders.
An Android device can have many different ContentProviders and many different SyncAdapters. Since a ContentResolver may not be part of the same .apk as a SyncAdapter, ContentResolver is a system service that finds the right ContentProvider to store a given kind of data. It does this using the ContentAuthority string, which uniquely identifies one specific ContentProvider. Moreover, each ContentProvider must be declared in AndroidManifest.xml
which ensures that it can be found by the ContentResolver. Within this declaration you can specify whether the ContentProvider can be used by other applications, see: android:exported
.
<provider
android:name=".CustomProvider"
android:authorities="com.example.app.provider"
android:exported="false"
android:multiprocess="true" >
</provider>
In this case, using an existing ContentProvider, you will need to look at the platform documentation to see what ContentAuthority string they use, and use the same string. If you're creating your own ContentProvider, you just need to ensure that the ContentAuthority you create is unique. The best way to do this is to use parts of your domain name (java class style) in the Authority. Write them in the reverse order. This is illustrated in their example... com.android.contacts
.
Solution 2:
When your APK gets loaded, the directives in the manifest tell the OS to review all meta-data. In this case, it is content meta data for Android contacts. The name that is used to find the provider is com.android.contacts (defined by Android) -- and the owner has the "authority" to provide the content access to its data base (i.e., the ContentProvider).
N.B. You could be a content provider of your own data that can be sync'ed with your web services that is not contacts. The meta-data is a mechanism to register with the OS so you can find it during a broadcast message.
This defined meta-data is going to be associated with your SyncAdapter by virtue of the 'sync type' that you provide. The name of the type is the android:accountType and might be 'com.mycompany.myapp'. That key is used during a broadcast to all sync adapters and your coded BroadcastReceiver will handle the message with your type.
That is the start of the relationships and some breakdown of the terminology.
Solution 3:
It is a way to create relation between an Account-type,Sync Adapter and a Content Authority
Looking back again at AndroidManifest, that strange meta-data tag in Sync service is the key piece that establishes the binding between a ContentAuthority and an account. It externally references another xml file (call it whatever you like, something relevant to your app.)
Let's look at sync_myapp.xml:
<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
android:contentAuthority="com.android.contacts"
android:accountType="com.example.android.samplesync"
android:supportsUploading="false"
android:userVisible="true" />
It tells Android that the sync adapter we've defined (the class that was called out in the name element of the tag that includes the tag that includes this file, will sync contacts using a com.example.android.samplesync style account. Account type and Authority is unique for your application.
All your contentAuthority strings have to all match, and match with what you're syncing -- This should be a string you define, if you're creating your own database, or you should use some existing device strings if you're syncing known data types (like contacts or calendar events or what have you.) The above ("com.android.contacts") happens to be the ContentAuthority string for contacts type data (surprise, surprise.)
accountType also has to match one of those known account types that are already entered, or it has to match one you're creating.
Last userVisible true means shown to user.