I recently had an opportunity to work with the Android SDK. This was my first foray into Android development and I found it interesting and rewarding. One of my tasks was to look into creating a sync adapter, responsible for syncing our local device storage with a RESTful service in the cloud. While a sync example is provided in the SDK and the Android javadocs are fruitful, there was still a certain lack of prescription that I find necessary when looking into a new technology. This blog will provide the necessary steps in a prescriptive format, hoping to help any others struggling with this topic.
Before getting started, I absolutely must recommend viewing the 2010 Google I/O presentation on Android REST Client Applications, presented by Virgil Dobjanschi. It’s a fantastic introduction into some of the concepts and recommended patterns for writing well design syncing applications. Along with this presentation and the sync adapter sample provided with the SDK, the following list should provide you ample ammunition to get a sync adapter up and running fairly quickly.
There are two important Android components that are required for your sync adapter, the basic being a ContentProvider. The content provider should contain data you want to sync. Content providers are generally backed by one of the storage mechanisms in Android: Shared Preferences, Internal Storage, External Storage, SQLite Database or network storage. Writing a content provider is outside the scope of this entry. However, the main thing to note when implementing a content provider is the authority you assign in the Android manifest. It will be used in another step to tie some of our components together. In this example, it’s com.captechventures.unanet seen in this snippet:
<provider android:name=".content.UnanetProvider" android:authorities="com.captechventures.unanet" android:enabled="true"></provider>
The other important component is that you must have an account registered with the Android OS that you intend to link to your sync adapter. The bad news is that there is no “stock” functionality to give you an easy way to provide an Account to the system. However, in the same Sync Adapter Example that comes with the SDK there is a lot of code you can borrow to give you Account functionality. Unless you desire a custom credentials screen, you can heist all the code in the com.example.android.samplesync.authenticator package with only a few minor changes. You’ll also need to snag the authenticator.xml from the resource directory. There is a reference to Constants.ACCOUNT_TYPE in the Authenticator class. Be sure to replace this value with your own account type value, such as com.captechventures.unanet.account which is what we used for our example. You’ll also need to change the accountType attribute in the authenticator.xml to match the value you just used for replacement.
3. Sync Adapter Descriptor
This is the file that ties your sync adapter to the content provider and the account. In the res/xml folder, you’ll need to place an xml file that describes your sync adapter. It doesn’t matter the name, the contents are what’s important (that was foreign to me). Here is my example, found in the res/xml folder and named syncadapter.xml:
<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android" android:contentAuthority="com.captechventures.unanet" android:accountType="com.captechventures.unanet.account" android:supportsUploading="false" />
Recognize the contentAuthority and accountType attributes and their values. This is how we tie our content provider and our account to our sync adapter.
4. Abstract Threaded Sync Adapter Implementation
You’ll need to implement an AbstractThreadedSyncAdapter. Here is where the meat of your sync logic will live/start. There’s no one right way for sync logic and it will be different from implementation to implementation. However, I highly recommend following one of the patterns Dobjanschi outlines in his presentation for managing the sync itself. Once you watch the presentation and absorb the information, it just “makes sense” and doesn’t seem like there could be a better way.
Be sure to use the SyncResult in your overridden onPerformSync method appropriately. Using the object in the appropriate manner will allow the sync manager to be more effective.
5. Sync Adapter Service
The syncing mechanism will run in the background on a different thread from the UI. To do this, we’ll need to setup a service that filters on sync intents. The service implementation is simple and only a few lines long. Follow the example in the Sync Adapter Sample, changing the types to match yours. Here is the declaration in the Android Manifest for my sample service, notice the addition of the intent filter and the android:resource reference to the Sync Adapter Descriptor we created in step 3:
<service android:name=".sync.SyncService" android:exported="true"> <intent-filter> <action android:name="android.content.SyncAdapter" /> </intent-filter> <meta-data android:name="android.content.SyncAdapter" android:resource="@xml/syncadapter" /> </service>
6. Android Manifest
The final piece is to pull everything together in your Android Manifest. We’ve already identified you’ll need your content provider as well as the Service responsible for reacting to sync manager requests declared. You’ll also need to provide a few permissions to allow several aspects of your application to function appropriately: ability to read/write accounts, ability to interact with the network, and ability to read/write sync settings. Here is a snippet from our sync adapter:
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.GET_ACCOUNTS" /> <uses-permission android:name="android.permission.USE_CREDENTIALS" /> <uses-permission android:name="android.permission.MANAGE_ACCOUNTS" /> <uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" /> <uses-permission android:name="android.permission.READ_SYNC_STATS" /> <uses-permission android:name="android.permission.READ_SYNC_SETTINGS" /> <uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
While this roadmap is aimed at kickstarting your sync adapter development, it by no means replaces reading and understanding the Android documentation on sync adapters and all the related classes and components. Be sure to read the documentation linked throughout this entry.