summaryrefslogtreecommitdiffstats
path: root/docs/html/training/sync-adapters/creating-sync-adapter.jd
blob: b13ce0718fa4f88a420cafe3da20e4b5d5d39f01 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
page.title=Creating a Sync Adapter

trainingnavtop=true
@jd:body

<div id="tb-wrapper">
<div id="tb">

<h2>This lesson teaches you to</h2>
<ol>
    <li>
        <a href="#CreateSyncAdapter"
        >Create the Sync Adapter Class</a>
    </li>
    <li>
        <a href="#CreateSyncAdapterService">Bind the Sync Adapter to the Framework</a>
    </li>
    <li>
        <a href="#CreateAccountTypeAccount"
        >Add the Account Required by the Framework</a>
    </li>
    <li>
        <a href="#CreateSyncAdapterMetadata">Add the Sync Adapter Metadata File</a>
    </li>
    <li>
        <a href="#DeclareSyncAdapterManifest">Declare the Sync Adapter in the Manifest</a>
    </li>
</ol>

<h2>You should also read</h2>
<ul>
    <li>
        <a href="{@docRoot}guide/components/bound-services.html">Bound Services</a>
    </li>
    <li>
        <a href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a>
    </li>
    <li>
        <a href="{@docRoot}training/id-auth/custom_auth.html">Creating a Custom Account Type</a>
    </li>
</ul>

<h2>Try it out</h2>

<div class="download-box">
 <a href="http://developer.android.com/shareables/training/BasicSyncAdapter.zip" class="button">Download the sample</a>
 <p class="filename">BasicSyncAdapter.zip</p>
</div>

</div>
</div>
<p>
    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:
<dl>
    <dt>
        Sync adapter class.
    </dt>
    <dd>
        A class that wraps your data transfer code in an interface compatible with the sync adapter
        framework.
    </dd>
    <dt>
        Bound {@link android.app.Service}.
    </dt>
    <dd>
        A component that allows the sync adapter framework to run the code in your sync adapter
        class.
    </dd>
    <dt>
        Sync adapter XML metadata file.
    </dt>
    <dd>
        A file containing information about your sync adapter. The framework reads this file to
        find out how to load and schedule your data transfer.
    </dd>
    <dt>
        Declarations in the app manifest.
    </dt>
    <dd>
        XML that declares the bound service and points to sync adapter-specific metadata.
    </dd>
</dl>
<p>
    This lesson shows you how to define these elements.
</p>
<h2 id="CreateSyncAdapter">Create a Sync Adapter Class</h2>
<p>
    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.
</p>
<h3>Extend the base sync adapter class AbstractThreadedSyncAdapter</h3>
<p>
    To create the sync adapter component, start by extending
    {@link android.content.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 {@link android.app.Activity#onCreate 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 {@link android.content.ContentResolver} instance. Since a second form of the
    constructor was added in Android platform version 3.0 to support the {@code parallelSyncs}
    argument, you need to create two forms of the constructor to maintain compatibility.
</p>
<p class="note">
    <strong>Note:</strong> 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
    <a href="#CreateSyncAdapterService">Bind the Sync Adapter to the Framework</a>.
</p>
<p>
    The following example shows you how to implement
    {@link android.content.AbstractThreadedSyncAdapter}and its constructors:
</p>
<pre style="clear: right">
/**
 * Handle the transfer of data between a server and an
 * app, using the Android sync adapter framework.
 */
public class SyncAdapter extends AbstractThreadedSyncAdapter {
    ...
    // Global variables
    // Define a variable to contain a content resolver instance
    ContentResolver mContentResolver;
    /**
     * Set up the sync adapter
     */
    public SyncAdapter(Context context, boolean autoInitialize) {
        super(context, autoInitialize);
        /*
         * If your app uses a content resolver, get an instance of it
         * from the incoming Context
         */
        mContentResolver = context.getContentResolver();
    }
    ...
    /**
     * Set up the sync adapter. This form of the
     * constructor maintains compatibility with Android 3.0
     * and later platform versions
     */
    public SyncAdapter(
            Context context,
            boolean autoInitialize,
            boolean allowParallelSyncs) {
        super(context, autoInitialize, allowParallelSyncs);
        /*
         * If your app uses a content resolver, get an instance of it
         * from the incoming Context
         */
        mContentResolver = context.getContentResolver();
        ...
    }
</pre>
<h3>Add the data transfer code to onPerformSync()</h3>
<p>
    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
    {@link android.content.AbstractThreadedSyncAdapter#onPerformSync onPerformSync()}.
</p>
<p>
    To facilitate the transfer of data from your main app code to the sync adapter component,
    the sync adapter framework calls
    {@link android.content.AbstractThreadedSyncAdapter#onPerformSync onPerformSync()} with the
    following arguments:
</p>
<dl>
    <dt>
        Account
    </dt>
    <dd>
        An {@link android.accounts.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.
    </dd>
    <dt>
        Extras
    </dt>
    <dd>
        A {@link android.os.Bundle} containing flags sent by the event that triggered the sync
        adapter.
    </dd>
    <dt>
        Authority
    </dt>
    <dd>
        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.
    </dd>
    <dt>
        Content provider client
    </dt>
    <dd>
        A {@link android.content.ContentProviderClient} for the content provider pointed to by the
        authority argument. A {@link android.content.ContentProviderClient} is a lightweight public
        interface to a content provider. It has the same basic functionality as a
        {@link android.content.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.
    </dd>
    <dt>
        Sync result
    </dt>
    <dd>
        A {@link android.content.SyncResult} object that you use to send information to the sync
        adapter framework.
    </dd>
</dl>
<p>
    The following snippet shows the overall structure of
    {@link android.content.AbstractThreadedSyncAdapter#onPerformSync onPerformSync()}:
</p>
<pre>
    /*
     * Specify the code you want to run in the sync adapter. The entire
     * sync adapter runs in a background thread, so you don't have to set
     * up your own background processing.
     */
    &#64;Override
    public void onPerformSync(
            Account account,
            Bundle extras,
            String authority,
            ContentProviderClient provider,
            SyncResult syncResult) {
    /*
     * Put the data transfer code here.
     */
    ...
    }
</pre>
<p>
    While the actual implementation of
    {@link android.content.AbstractThreadedSyncAdapter#onPerformSync onPerformSync()} is specific to
    your app's data synchronization requirements and server connection protocols, there are a few
    general tasks your implementation should perform:
</p>
<dl>
    <dt>
        Connecting to a server
    </dt>
    <dd>
        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.
    </dd>
    <dt>
        Downloading and uploading data
    </dt>
    <dd>
        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.
    </dd>
    <dt>
        Handling data conflicts or determining how current the data is
    </dt>
    <dd>
        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.
    </dd>
    <dt>
        Clean up.
    </dt>
    <dd>
        Always close connections to a server and clean up temp files and caches at the end of
        your data transfer.
    </dd>
</dl>
<p class="note">
    <strong>Note:</strong> The sync adapter framework runs
    {@link android.content.AbstractThreadedSyncAdapter#onPerformSync onPerformSync()} on a
    background thread, so you don't have to set up your own background processing.
</p>
<p>
    In addition to your sync-related tasks, you should try to combine your regular
    network-related tasks and add them to
    {@link android.content.AbstractThreadedSyncAdapter#onPerformSync 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 <a href="{@docRoot}training/efficient-downloads/index.html"
    >Transferring Data Without Draining the Battery</a>, which describes several network access
    tasks you can include in your data transfer code.
</p>
<h2 id="CreateSyncAdapterService">Bind the Sync Adapter to the Framework</h2>
<p>
    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
    {@link android.app.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
    {@link android.content.AbstractThreadedSyncAdapter#onPerformSync onPerformSync()} method and
    pass data to it.
</p>
<p>
    Instantiate your sync adapter component as a singleton in the
    {@link android.app.Service#onCreate onCreate()} method of the service. By instantiating
    the component in {@link android.app.Service#onCreate 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.
</p>
<p>
    For example, the following snippet shows you how to create a class that implements the
    bound {@link android.app.Service}, instantiates your sync adapter component, and gets the
    Android binder object:
</p>
<pre>
package com.example.android.syncadapter;
/**
 * Define a Service that returns an {@link android.os.IBinder} for the
 * sync adapter class, allowing the sync adapter framework to call
 * onPerformSync().
 */
public class SyncService extends Service {
    // Storage for an instance of the sync adapter
    private static SyncAdapter sSyncAdapter = null;
    // Object to use as a thread-safe lock
    private static final Object sSyncAdapterLock = new Object();
    /*
     * Instantiate the sync adapter object.
     */
    &#64;Override
    public void onCreate() {
        /*
         * Create the sync adapter as a singleton.
         * Set the sync adapter as syncable
         * Disallow parallel syncs
         */
        synchronized (sSyncAdapterLock) {
            if (sSyncAdapter == null) {
                sSyncAdapter = new SyncAdapter(getApplicationContext(), true);
            }
        }
    }
    /**
     * Return an object that allows the system to invoke
     * the sync adapter.
     *
     */
    &#64;Override
    public IBinder onBind(Intent intent) {
        /*
         * Get the object that allows external processes
         * to call onPerformSync(). The object is created
         * in the base class code when the SyncAdapter
         * constructors call super()
         */
        return sSyncAdapter.getSyncAdapterBinder();
    }
}
</pre>
<p class="note">
    <strong>Note:</strong> To see a more detailed example of a bound service for a sync adapter,
    see the sample app.
</p>
<h2 id="CreateAccountTypeAccount">Add the Account Required by the Framework</h2>
<p>
    The sync adapter framework requires each sync adapter to have an account type. You declared
    the account type value in the section
    <a href="creating-authenticator.html#CreateAuthenticatorFile"
    >Add the Authenticator Metadata File</a>. 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 {@link android.accounts.AccountManager#addAccountExplicitly addAccountExplicitly()}.
</p>
<p>
    The best place to call the method is in the
    {@link android.support.v4.app.FragmentActivity#onCreate onCreate()} method of your app's
    opening activity. The following code snippet shows you how to do this:
</p>
<pre>
public class MainActivity extends FragmentActivity {
    ...
    ...
    // Constants
    // The authority for the sync adapter's content provider
    public static final String AUTHORITY = "com.example.android.datasync.provider"
    // An account type, in the form of a domain name
    public static final String ACCOUNT_TYPE = "example.com";
    // The account name
    public static final String ACCOUNT = "dummyaccount";
    // Instance fields
    Account mAccount;
    ...
    &#64;Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ...
        // Create the dummy account
        mAccount = CreateSyncAccount(this);
        ...
    }
    ...
    /**
     * Create a new dummy account for the sync adapter
     *
     * @param context The application context
     */
    public static Account CreateSyncAccount(Context context) {
        // Create the account type and default account
        Account newAccount = new Account(
                ACCOUNT, ACCOUNT_TYPE);
        // Get an instance of the Android account manager
        AccountManager accountManager =
                (AccountManager) context.getSystemService(
                        ACCOUNT_SERVICE);
        /*
         * Add the account and account type, no password or user data
         * If successful, return the Account object, otherwise report an error.
         */
        if (accountManager.addAccountExplicitly(newAccount, null, null))) {
            /*
             * If you don't set android:syncable="true" in
             * in your &lt;provider&gt; element in the manifest,
             * then call context.setIsSyncable(account, AUTHORITY, 1)
             * here.
             */
        } else {
            /*
             * The account exists or some other error occurred. Log this, report it,
             * or handle it internally.
             */
        }
    }
    ...
}
</pre>
<h2 id="CreateSyncAdapterMetadata">Add the Sync Adapter Metadata File</h2>
<p>
    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 {@code /res/xml/} directory in your app project. You can give any name to the file,
    although it's usually called {@code syncadapter.xml}.
</p>
<p>
    This XML file contains a single XML element <code>&lt;sync-adapter&gt;</code> that has the
    following attributes:
</p>
<dl>
    <dt><code>android:contentAuthority</code></dt>
    <dd>
        The URI authority for your content provider. If you created a stub content provider for
        your app in the previous lesson <a href="creating-stub-provider.html"
        >Creating a Stub Content Provider</a>, use the value you specified for the
        attribute
<code><a href="{@docRoot}guide/topics/manifest/provider-element.html#auth">android:authorities</a></code>
        in the <code><a href="{@docRoot}guide/topics/manifest/provider-element.html"
        >&lt;provider&gt;</a></code> element you added to your app manifest. This attribute is
        described in more detail in the section
        <a href="creating-stub-provider.html#DeclareProvider"
        >Declare the Provider in the Manifest</a>.
        <br/>
        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
<code><a href="{@docRoot}guide/topics/manifest/provider-element.html#auth">android:authorities</a></code>
        attribute of the <code><a href="{@docRoot}guide/topics/manifest/provider-element.html"
        >&lt;provider&gt;</a></code> element that declares your provider in your app manifest.
    </dd>
    <dt><code>android:accountType</code></dt>
    <dd>
        The account type required by the sync adapter framework. The value must be the same
        as the account type value you provided when you created the authenticator metadata file, as
        described in the section <a href="creating-authenticator.html#CreateAuthenticatorFile"
        >Add the Authenticator Metadata File</a>. It's also the value you specified for the
        constant {@code ACCOUNT_TYPE} in the code snippet in the section
        <a href="#CreateAccountTypeAccount">Add the Account Required by the Framework</a>.
    </dd>
    <dt>Settings attributes</dt>
    <dd>
        <dl>
            <dt>
                {@code android:userVisible}
            </dt>
            <dd>
                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
                <b>Accounts</b> 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.
            </dd>
            <dt>
                {@code android:supportsUploading}
            </dt>
            <dd>
                Allows you to upload data to the cloud. Set this to {@code false} if your app only
                downloads data.
            </dd>
            <dt>
                {@code android:allowParallelSyncs}
            </dt>
            <dd>
                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.
            </dd>
            <dt>
                {@code android:isAlwaysSyncable}
            </dt>
            <dd>
                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 {@code false}, and then call
                {@link android.content.ContentResolver#requestSync requestSync()} to run the
                sync adapter. To learn more about running a sync adapter, see the lesson
                <a href="running-sync-adapter.html">Running a Sync Adapter</a>
            </dd>
        </dl>
    </dd>
</dl>
<p>
    The following example shows the XML for a sync adapter that uses a single dummy account and
    only does downloads.
</p>
<pre>
&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;sync-adapter
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:contentAuthority="com.example.android.datasync.provider"
        android:accountType="com.android.example.datasync"
        android:userVisible="false"
        android:supportsUploading="false"
        android:allowParallelSyncs="false"
        android:isAlwaysSyncable="true"/&gt;
</pre>

<h2 id="DeclareSyncAdapterManifest">Declare the Sync Adapter in the Manifest</h2>
<p>
    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 {@link android.app.Service}
    you've added.
</p>
<p>
    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 <a href="creating-authenticator.html">Creating a Stub Authenticator</a>.
</p>
<p>
    To request these permissions, add the following to your app manifest as child elements of
<code><a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a></code>:
</p>
<dl>
    <dt>
        {@link android.Manifest.permission#INTERNET android.permission.INTERNET}
    </dt>
    <dd>
        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.
    </dd>
    <dt>
{@link android.Manifest.permission#READ_SYNC_SETTINGS android.permission.READ_SYNC_SETTINGS}
    </dt>
    <dd>
        Allows your app to read the current sync adapter settings. For example, you need this
        permission in order to call {@link android.content.ContentResolver#getIsSyncable
        getIsSyncable()}.
    </dd>
    <dt>
{@link android.Manifest.permission#WRITE_SYNC_SETTINGS android.permission.WRITE_SYNC_SETTINGS}
    </dt>
    <dd>
        Allows your app to control sync adapter settings. You need this permission in order to
        set periodic sync adapter runs using {@link android.content.ContentResolver#addPeriodicSync
        addPeriodicSync()}. This permission is <b>not</b> required to call
        {@link android.content.ContentResolver#requestSync requestSync()}. To learn more about
        running the sync adapter, see <a href="running-sync-adapter.html"
        >Running A Sync Adapter</a>.
    </dd>
    <dt>
{@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS android.permission.AUTHENTICATE_ACCOUNTS}
    </dt>
    <dd>
        Allows you to use the authenticator component you created in the lesson
        <a href="creating-authenticator.html">Creating a Stub Authenticator</a>.
    </dd>
</dl>
<p>
    The following snippet shows how to add the permissions:
</p>
<pre>
&lt;manifest&gt;
...
    &lt;uses-permission
            android:name="android.permission.INTERNET"/&gt;
    &lt;uses-permission
            android:name="android.permission.READ_SYNC_SETTINGS"/&gt;
    &lt;uses-permission
            android:name="android.permission.WRITE_SYNC_SETTINGS"/&gt;
    &lt;uses-permission
            android:name="android.permission.AUTHENTICATE_ACCOUNTS"/&gt;
...
&lt;/manifest&gt;
</pre>
<p>
    Finally, to declare the bound {@link android.app.Service} that the framework uses to
    interact with your sync adapter, add the following XML to your app manifest as a child element
    of <code><a href="{@docRoot}guide/topics/manifest/application-element.html"
    >&lt;application&gt;</a></code>:
</p>
<pre>
        &lt;service
                android:name="com.example.android.datasync.SyncService"
                android:exported="true"
                android:process=":sync"&gt;
            &lt;intent-filter&gt;
                &lt;action android:name="android.content.SyncAdapter"/&gt;
            &lt;/intent-filter&gt;
            &lt;meta-data android:name="android.content.SyncAdapter"
                    android:resource="&#64;xml/syncadapter" /&gt;
        &lt;/service&gt;
</pre>
<p>
    The
<code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a></code>
    element sets up a filter that's triggered by the intent action
    {@code 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
    {@code SyncService}. The attribute
<code><a href="{@docRoot}guide/topics/manifest/service-element.html#exported">android:exported="true"</a></code>
    allows processes other than your app (including the system) to access the
    {@link android.app.Service}. The attribute
<code><a href="{@docRoot}guide/topics/manifest/service-element.html#proc">android:process=":sync"</a></code>
    tells the system to run the {@link android.app.Service} in a global shared process named
    {@code sync}. If you have multiple sync adapters in your app they can share this process,
    which reduces overhead.
</p>
<p>
    The
<code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html">&lt;meta-data&gt;</a></code>
    element provides provides the name of the sync adapter metadata XML file you created previously.
    The
<code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html#nm">android:name</a></code>
    attribute indicates that this metadata is for the sync adapter framework. The
<code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html#rsrc">android:resource</a></code>
    element specifies the name of the metadata file.
</p>
<p>
    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.
</p>