Joe Malin | e9df511 | 2013-06-07 13:38:00 -0700 | [diff] [blame] | 1 | page.title=Running a Sync Adapter |
| 2 | |
| 3 | trainingnavtop=true |
| 4 | @jd:body |
| 5 | |
| 6 | |
| 7 | <div id="tb-wrapper"> |
| 8 | <div id="tb"> |
| 9 | |
| 10 | <h2>This lesson teaches you how to:</h2> |
| 11 | <ol> |
| 12 | <li><a href="#RunByMessage">Run the Sync Adapter When Server Data Changes</a> |
| 13 | <li><a href="#RunDataChange">Run the Sync Adapter When Content Provider Data Changes</a></li> |
| 14 | <li><a href="#RunByNetwork">Run the Sync Adapter After a Network Message</a></li> |
| 15 | <li><a href="#RunPeriodic">Run the Sync Adapter Periodically</a></li> |
| 16 | <li><a href="#RunOnDemand">Run the Sync Adapter On Demand</a></li> |
| 17 | </ol> |
| 18 | |
| 19 | |
| 20 | <h2>You should also read</h2> |
| 21 | <ul> |
| 22 | <li> |
| 23 | <a href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a> |
| 24 | </li> |
| 25 | </ul> |
| 26 | |
| 27 | <h2>Try it out</h2> |
| 28 | |
| 29 | <div class="download-box"> |
| 30 | <a href="http://developer.android.com/shareables/training/BasicSyncAdapter.zip" class="button">Download the sample</a> |
| 31 | <p class="filename">BasicSyncAdapter.zip</p> |
| 32 | </div> |
| 33 | |
| 34 | </div> |
| 35 | </div> |
| 36 | <p> |
| 37 | In the previous lessons in this class, you learned how to create a sync adapter component that |
| 38 | encapsulates data transfer code, and how to add the additional components that allow you to |
| 39 | plug the sync adapter into the system. You now have everything you need to install an app that |
| 40 | includes a sync adapter, but none of the code you've seen actually runs the sync adapter. |
| 41 | </p> |
| 42 | <p> |
| 43 | You should try to run your sync adapter based on a schedule or as the indirect result of some |
| 44 | event. For example, you may want your sync adapter to run on a regular schedule, either after a |
| 45 | certain period of time or at a particular time of the day. You may also want to run your sync |
| 46 | adapter when there are changes to data stored on the device. You should avoid running your |
| 47 | sync adapter as the direct result of a user action, because by doing this you don't get the full |
| 48 | benefit of the sync adapter framework's scheduling ability. For example, you should avoid |
| 49 | providing a refresh button in your user interface. |
| 50 | </p> |
| 51 | <p> |
| 52 | You have the following options for running your sync adapter: |
| 53 | </p> |
| 54 | <dl> |
| 55 | <dt> |
| 56 | When server data changes |
| 57 | </dt> |
| 58 | <dd> |
| 59 | Run the sync adapter in response to a message from a server, indicating that server-based |
| 60 | data has changed. This option allows you to refresh data from the server to the device |
| 61 | without degrading performance or wasting battery life by polling the server. |
| 62 | </dd> |
| 63 | <dt>When device data changes</dt> |
| 64 | <dd> |
| 65 | Run a sync adapter when data changes on the device. This option allows you to send |
| 66 | modified data from the device to a server, and is especially useful if you need to ensure |
| 67 | that the server always has the latest device data. This option is straightforward to |
| 68 | implement if you actually store data in your content provider. If you're using a stub |
| 69 | content provider, detecting data changes may be more difficult. |
| 70 | </dd> |
| 71 | <dt> |
| 72 | When the system sends out a network message |
| 73 | </dt> |
| 74 | <dd> |
| 75 | Run a sync adapter when the Android system sends out a network message that keeps the |
| 76 | TCP/IP connection open; this message is a basic part of the networking framework. Using |
| 77 | this option is one way to run the sync adapter automatically. Consider using it in |
| 78 | conjunction with interval-based sync adapter runs. |
| 79 | </dd> |
| 80 | <dt> |
| 81 | At regular intervals |
| 82 | </dt> |
| 83 | <dd> |
| 84 | Run a sync adapter after the expiration of an interval you choose, or run it at a certain |
| 85 | time every day. |
| 86 | </dd> |
| 87 | <dt>On demand</dt> |
| 88 | <dd> |
| 89 | Run the sync adapter in response to a user action. However, to provide the best user |
| 90 | experience you should rely primarily on one of the more automated options. By using |
| 91 | automated options, you conserve battery and network resources. |
| 92 | </dd> |
| 93 | </dl> |
| 94 | <p> |
| 95 | The rest of this lesson describes each of the options in more detail. |
| 96 | </p> |
| 97 | <h2 id="RunByMessage">Run the Sync Adapter When Server Data Changes</h2> |
| 98 | <p> |
| 99 | If your app transfers data from a server and the server data changes frequently, you can use |
| 100 | a sync adapter to do downloads in response to data changes. To run the sync adapter, have |
| 101 | the server send a special message to a {@link android.content.BroadcastReceiver} in your app. |
| 102 | In response to this message, call {@link android.content.ContentResolver#requestSync |
| 103 | ContentResolver.requestSync()} to signal the sync adapter framework to run your |
| 104 | sync adapter. |
| 105 | </p> |
| 106 | <p> |
| 107 | <a href="{@docRoot}google/gcm/index.html">Google Cloud Messaging</a> (GCM) provides both the |
| 108 | server and device components you need to make this messaging system work. Using GCM to trigger |
| 109 | transfers is more reliable and more efficient than polling servers for status. While polling |
| 110 | requires a {@link android.app.Service} that is always active, GCM uses a |
| 111 | {@link android.content.BroadcastReceiver} that's activated when a message arrives. While polling |
| 112 | at regular intervals uses battery power even if no updates are available, GCM only sends |
| 113 | messages when needed. |
| 114 | </p> |
| 115 | <p class="note"> |
| 116 | <strong>Note:</strong> If you use GCM to trigger your sync adapter via a broadcast to all |
| 117 | devices where your app is installed, remember that they receive your message at |
| 118 | roughly the same time. This situation can cause multiple instance of your sync adapter to run |
| 119 | at the same time, causing server and network overload. To avoid this situation for a broadcast |
| 120 | to all devices, you should consider deferring the start of the sync adapter for a period |
| 121 | that's unique for each device. |
| 122 | <p> |
| 123 | The following code snippet shows you how to run |
| 124 | {@link android.content.ContentResolver#requestSync requestSync()} in response to an |
| 125 | incoming GCM message: |
| 126 | </p> |
| 127 | <pre> |
| 128 | public class GcmBroadcastReceiver extends BroadcastReceiver { |
| 129 | ... |
| 130 | // Constants |
| 131 | // Content provider authority |
| 132 | public static final String AUTHORITY = "com.example.android.datasync.provider" |
| 133 | // Account type |
| 134 | public static final String ACCOUNT_TYPE = "com.example.android.datasync"; |
| 135 | // Account |
| 136 | public static final String ACCOUNT = "default_account"; |
| 137 | // Incoming Intent key for extended data |
| 138 | public static final String KEY_SYNC_REQUEST = |
| 139 | "com.example.android.datasync.KEY_SYNC_REQUEST"; |
| 140 | ... |
| 141 | @Override |
| 142 | public void onReceive(Context context, Intent intent) { |
| 143 | // Get a GCM object instance |
| 144 | GoogleCloudMessaging gcm = |
| 145 | GoogleCloudMessaging.getInstance(context); |
| 146 | // Get the type of GCM message |
| 147 | String messageType = gcm.getMessageType(intent); |
| 148 | /* |
| 149 | * Test the message type and examine the message contents. |
| 150 | * Since GCM is a general-purpose messaging system, you |
| 151 | * may receive normal messages that don't require a sync |
| 152 | * adapter run. |
| 153 | * The following code tests for a a boolean flag indicating |
| 154 | * that the message is requesting a transfer from the device. |
| 155 | */ |
| 156 | if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(messageType) |
| 157 | && |
| 158 | intent.getBooleanExtra(KEY_SYNC_REQUEST)) { |
| 159 | /* |
| 160 | * Signal the framework to run your sync adapter. Assume that |
| 161 | * app initialization has already created the account. |
| 162 | */ |
| 163 | ContentResolver.requestSync(ACCOUNT, AUTHORITY, null); |
| 164 | ... |
| 165 | } |
| 166 | ... |
| 167 | } |
| 168 | ... |
| 169 | } |
| 170 | </pre> |
| 171 | <h2 id="RunDataChange">Run the Sync Adapter When Content Provider Data Changes</h2> |
| 172 | <p> |
| 173 | If your app collects data in a content provider, and you want to update the server whenever |
| 174 | you update the provider, you can set up your app to run your sync adapter automatically. To do |
| 175 | this, you register an observer for the content provider. When data in your content provider |
| 176 | changes, the content provider framework calls the observer. In the observer, call |
| 177 | {@link android.content.ContentResolver#requestSync requestSync()} to tell the framework to run |
| 178 | your sync adapter. |
| 179 | </p> |
| 180 | <p class="note"> |
| 181 | <strong>Note:</strong> If you're using a stub content provider, you don't have any data in |
| 182 | the content provider and {@link android.database.ContentObserver#onChange onChange()} is |
| 183 | never called. In this case, you have to provide your own mechanism for detecting changes to |
| 184 | device data. This mechanism is also responsible for calling |
| 185 | {@link android.content.ContentResolver#requestSync requestSync()} when the data changes. |
| 186 | </p> |
| 187 | <p> |
| 188 | To create an observer for your content provider, extend the class |
| 189 | {@link android.database.ContentObserver} and implement both forms of its |
| 190 | {@link android.database.ContentObserver#onChange onChange()} method. In |
| 191 | {@link android.database.ContentObserver#onChange onChange()}, call |
| 192 | {@link android.content.ContentResolver#requestSync requestSync()} to start the sync adapter. |
| 193 | </p> |
| 194 | <p> |
| 195 | To register the observer, pass it as an argument in a call to |
| 196 | {@link android.content.ContentResolver#registerContentObserver registerContentObserver()}. In |
| 197 | this call, you also have to pass in a content URI for the data you want to watch. The content |
| 198 | provider framework compares this watch URI to content URIs passed in as arguments to |
| 199 | {@link android.content.ContentResolver} methods that modify your provider, such as |
| 200 | {@link android.content.ContentResolver#insert ContentResolver.insert()}. If there's a match, your |
| 201 | implementation of {@link android.database.ContentObserver#onChange ContentObserver.onChange()} |
| 202 | is called. |
| 203 | </p> |
| 204 | |
| 205 | <p> |
| 206 | The following code snippet shows you how to define a {@link android.database.ContentObserver} |
| 207 | that calls {@link android.content.ContentResolver#requestSync requestSync()} when a table |
| 208 | changes: |
| 209 | </p> |
| 210 | <pre> |
| 211 | public class MainActivity extends FragmentActivity { |
| 212 | ... |
| 213 | // Constants |
| 214 | // Content provider scheme |
| 215 | public static final String SCHEME = "content://"; |
| 216 | // Content provider authority |
| 217 | public static final String AUTHORITY = "com.example.android.datasync.provider"; |
| 218 | // Path for the content provider table |
| 219 | public static final String TABLE_PATH = "data_table"; |
| 220 | // Account |
| 221 | public static final String ACCOUNT = "default_account"; |
| 222 | // Global variables |
| 223 | // A content URI for the content provider's data table |
| 224 | Uri mUri; |
| 225 | // A content resolver for accessing the provider |
| 226 | ContentResolver mResolver; |
| 227 | ... |
| 228 | public class TableObserver extends ContentObserver { |
| 229 | /* |
| 230 | * Define a method that's called when data in the |
| 231 | * observed content provider changes. |
| 232 | * This method signature is provided for compatibility with |
| 233 | * older platforms. |
| 234 | */ |
| 235 | @Override |
| 236 | public void onChange(boolean selfChange) { |
| 237 | /* |
| 238 | * Invoke the method signature available as of |
| 239 | * Android platform version 4.1, with a null URI. |
| 240 | */ |
| 241 | onChange(selfChange, null); |
| 242 | } |
| 243 | /* |
| 244 | * Define a method that's called when data in the |
| 245 | * observed content provider changes. |
| 246 | */ |
| 247 | @Override |
| 248 | public void onChange(boolean selfChange, Uri changeUri) { |
| 249 | /* |
| 250 | * Ask the framework to run your sync adapter. |
| 251 | * To maintain backward compatibility, assume that |
| 252 | * changeUri is null. |
| 253 | ContentResolver.requestSync(ACCOUNT, AUTHORITY, null); |
| 254 | } |
| 255 | ... |
| 256 | } |
| 257 | ... |
| 258 | @Override |
| 259 | protected void onCreate(Bundle savedInstanceState) { |
| 260 | super.onCreate(savedInstanceState); |
| 261 | ... |
| 262 | // Get the content resolver object for your app |
| 263 | mResolver = getContentResolver(); |
| 264 | // Construct a URI that points to the content provider data table |
| 265 | mUri = new Uri.Builder() |
| 266 | .scheme(SCHEME) |
| 267 | .authority(AUTHORITY) |
| 268 | .path(TABLE_PATH) |
| 269 | .build(); |
| 270 | /* |
| 271 | * Create a content observer object. |
| 272 | * Its code does not mutate the provider, so set |
| 273 | * selfChange to "false" |
| 274 | */ |
| 275 | TableObserver observer = new TableObserver(false); |
| 276 | /* |
| 277 | * Register the observer for the data table. The table's path |
| 278 | * and any of its subpaths trigger the observer. |
| 279 | */ |
| 280 | mResolver.registerContentObserver(mUri, true, observer); |
| 281 | ... |
| 282 | } |
| 283 | ... |
| 284 | } |
| 285 | </pre> |
| 286 | <h2 id="RunByNetwork">Run the Sync Adapter After a Network Message</h2> |
| 287 | <p> |
| 288 | When a network connection is available, the Android system sends out a message |
| 289 | every few seconds to keep the device's TCP/IP connection open. This message also goes to |
| 290 | the {@link android.content.ContentResolver} of each app. By calling |
| 291 | {@link android.content.ContentResolver#setSyncAutomatically setSyncAutomatically()}, |
| 292 | you can run the sync adapter whenever the {@link android.content.ContentResolver} |
| 293 | receives the message. |
| 294 | </p> |
| 295 | <p> |
| 296 | By scheduling your sync adapter to run when the network message is sent, you ensure that your |
| 297 | sync adapter is always scheduled to run while the network is available. Use this option if you |
| 298 | don't have to force a data transfer in response to data changes, but you do want to ensure |
| 299 | your data is regularly updated. Similarly, you can use this option if you don't want a fixed |
| 300 | schedule for your sync adapter, but you do want it to run frequently. |
| 301 | </p> |
| 302 | <p> |
| 303 | Since the method |
| 304 | {@link android.content.ContentResolver#setSyncAutomatically setSyncAutomatically()} |
| 305 | doesn't disable {@link android.content.ContentResolver#addPeriodicSync addPeriodicSync()}, your |
| 306 | sync adapter may be triggered repeatedly in a short period of time. If you do want to run |
| 307 | your sync adapter periodically on a regular schedule, you should disable |
| 308 | {@link android.content.ContentResolver#setSyncAutomatically setSyncAutomatically()}. |
| 309 | </p> |
| 310 | <p> |
| 311 | The following code snippet shows you how to configure your |
| 312 | {@link android.content.ContentResolver} to run your sync adapter in response to a network |
| 313 | message: |
| 314 | </p> |
| 315 | <pre> |
| 316 | public class MainActivity extends FragmentActivity { |
| 317 | ... |
| 318 | // Constants |
| 319 | // Content provider authority |
| 320 | public static final String AUTHORITY = "com.example.android.datasync.provider"; |
| 321 | // Account |
| 322 | public static final String ACCOUNT = "default_account"; |
| 323 | // Global variables |
| 324 | // A content resolver for accessing the provider |
| 325 | ContentResolver mResolver; |
| 326 | ... |
| 327 | @Override |
| 328 | protected void onCreate(Bundle savedInstanceState) { |
| 329 | super.onCreate(savedInstanceState); |
| 330 | ... |
| 331 | // Get the content resolver for your app |
| 332 | mResolver = getContentResolver(); |
| 333 | // Turn on automatic syncing for the default account and authority |
| 334 | mResolver.setSyncAutomatically(ACCOUNT, AUTHORITY, true); |
| 335 | ... |
| 336 | } |
| 337 | ... |
| 338 | } |
| 339 | </pre> |
| 340 | <h2 id="RunPeriodic">Run the Sync Adapter Periodically</h2> |
| 341 | <p> |
| 342 | You can run your sync adapter periodically by setting a period of time to wait between runs, |
| 343 | or by running it at certain times of the day, or both. Running your sync adapter |
| 344 | periodically allows you to roughly match the update interval of your server. |
| 345 | </p> |
| 346 | <p> |
| 347 | Similarly, you can upload data from the device when your server is relatively idle, by |
| 348 | scheduling your sync adapter to run at night. Most users leave their powered on and plugged in |
| 349 | at night, so this time is usually available. Moreover, the device is not running other tasks at |
| 350 | the same time as your sync adapter. If you take this approach, however, you need to ensure that |
| 351 | each device triggers a data transfer at a slightly different time. If all devices run your |
| 352 | sync adapter at the same time, you are likely to overload your server and cell provider data |
| 353 | networks. |
| 354 | </p> |
| 355 | <p> |
| 356 | In general, periodic runs make sense if your users don't need instant updates, but expect to |
| 357 | have regular updates. Periodic runs also make sense if you want to balance the availability of |
| 358 | up-to-date data with the efficiency of smaller sync adapter runs that don't over-use device |
| 359 | resources. |
| 360 | </p> |
| 361 | <p> |
| 362 | To run your sync adapter at regular intervals, call |
| 363 | {@link android.content.ContentResolver#addPeriodicSync addPeriodicSync()}. This schedules your |
| 364 | sync adapter to run after a certain amount of time has elapsed. Since the sync adapter framework |
| 365 | has to account for other sync adapter executions and tries to maximize battery efficiency, the |
| 366 | elapsed time may vary by a few seconds. Also, the framework won't run your sync adapter if the |
| 367 | network is not available. |
| 368 | </p> |
| 369 | <p> |
| 370 | Notice that {@link android.content.ContentResolver#addPeriodicSync addPeriodicSync()} doesn't |
| 371 | run the sync adapter at a particular time of day. To run your sync adapter at roughly the |
| 372 | same time every day, use a repeating alarm as a trigger. Repeating alarms are described in more |
| 373 | detail in the reference documentation for {@link android.app.AlarmManager}. If you use the |
| 374 | method {@link android.app.AlarmManager#setInexactRepeating setInexactRepeating()} to set |
| 375 | time-of-day triggers that have some variation, you should still randomize the start time to |
| 376 | ensure that sync adapter runs from different devices are staggered. |
| 377 | </p> |
| 378 | <p> |
| 379 | The method {@link android.content.ContentResolver#addPeriodicSync addPeriodicSync()} doesn't |
| 380 | disable {@link android.content.ContentResolver#setSyncAutomatically setSyncAutomatically()}, |
| 381 | so you may get multiple sync runs in a relatively short period of time. Also, only a few |
| 382 | sync adapter control flags are allowed in a call to |
| 383 | {@link android.content.ContentResolver#addPeriodicSync addPeriodicSync()}; the flags that are |
| 384 | not allowed are described in the referenced documentation for |
| 385 | {@link android.content.ContentResolver#addPeriodicSync addPeriodicSync()}. |
| 386 | </p> |
| 387 | <p> |
| 388 | The following code snippet shows you how to schedule periodic sync adapter runs: |
| 389 | </p> |
| 390 | <pre> |
| 391 | public class MainActivity extends FragmentActivity { |
| 392 | ... |
| 393 | // Constants |
| 394 | // Content provider authority |
| 395 | public static final String AUTHORITY = "com.example.android.datasync.provider"; |
| 396 | // Account |
| 397 | public static final String ACCOUNT = "default_account"; |
| 398 | // Sync interval constants |
| 399 | public static final long MILLISECONDS_PER_SECOND = 1000L; |
| 400 | public static final long SECONDS_PER_MINUTE = 60L; |
| 401 | public static final long SYNC_INTERVAL_IN_MINUTES = 60L; |
| 402 | public static final long SYNC_INTERVAL = |
| 403 | SYNC_INTERVAL_IN_MINUTES * |
| 404 | SECONDS_PER_MINUTE * |
| 405 | MILLISECONDS_PER_SECOND; |
| 406 | // Global variables |
| 407 | // A content resolver for accessing the provider |
| 408 | ContentResolver mResolver; |
| 409 | ... |
| 410 | @Override |
| 411 | protected void onCreate(Bundle savedInstanceState) { |
| 412 | super.onCreate(savedInstanceState); |
| 413 | ... |
| 414 | // Get the content resolver for your app |
| 415 | mResolver = getContentResolver(); |
| 416 | /* |
| 417 | * Turn on periodic syncing |
| 418 | */ |
| 419 | ContentResolver.addPeriodicSync( |
| 420 | ACCOUNT, |
| 421 | AUTHORITY, |
| 422 | null, |
| 423 | SYNC_INTERVAL); |
| 424 | ... |
| 425 | } |
| 426 | ... |
| 427 | } |
| 428 | </pre> |
| 429 | <h2 id="RunOnDemand">Run the Sync Adapter On Demand</h2> |
| 430 | <p> |
| 431 | Running your sync adapter in response to a user request is the least preferable strategy |
| 432 | for running a sync adapter. The framework is specifically designed to conserve battery power |
| 433 | when it runs sync adapters according to a schedule. Options that run a sync in response to data |
| 434 | changes use battery power effectively, since the power is used to provide new data. |
| 435 | </p> |
| 436 | <p> |
| 437 | In comparison, allowing users to run a sync on demand means that the sync runs by itself, which |
| 438 | is inefficient use of network and power resources. Also, providing sync on demand leads users to |
| 439 | request a sync even if there's no evidence that the data has changed, and running a sync that |
| 440 | doesn't refresh data is an ineffective use of battery power. In general, your app should either |
| 441 | use other signals to trigger a sync or schedule them at regular intervals, without user input. |
| 442 | </p> |
| 443 | <p> |
| 444 | However, if you still want to run the sync adapter on demand, set the sync adapter flags for a |
| 445 | manual sync adapter run, then call |
| 446 | {@link android.content.ContentResolver#requestSync ContentResolver.requestSync()}. |
| 447 | </p> |
| 448 | <p> |
| 449 | Run on demand transfers with the following flags: |
| 450 | </p> |
| 451 | <dl> |
| 452 | <dt> |
| 453 | {@link android.content.ContentResolver#SYNC_EXTRAS_MANUAL SYNC_EXTRAS_MANUAL} |
| 454 | </dt> |
| 455 | <dd> |
| 456 | Forces a manual sync. The sync adapter framework ignores the existing settings, |
| 457 | such as the flag set by {@link android.content.ContentResolver#setSyncAutomatically |
| 458 | setSyncAutomatically()}. |
| 459 | </dd> |
| 460 | <dt> |
| 461 | {@link android.content.ContentResolver#SYNC_EXTRAS_EXPEDITED SYNC_EXTRAS_EXPEDITED} |
| 462 | </dt> |
| 463 | <dd> |
| 464 | Forces the sync to start immediately. If you don't set this, the system may wait several |
| 465 | seconds before running the sync request, because it tries to optimize battery use by |
| 466 | scheduling many requests in a short period of time. |
| 467 | </dd> |
| 468 | </dl> |
| 469 | <p> |
| 470 | The following code snippet shows you how to call |
| 471 | {@link android.content.ContentResolver#requestSync requestSync()} in response to a button |
| 472 | click: |
| 473 | </p> |
| 474 | <pre> |
| 475 | public class MainActivity extends FragmentActivity { |
| 476 | ... |
| 477 | // Constants |
| 478 | // Content provider authority |
| 479 | public static final String AUTHORITY = |
| 480 | "com.example.android.datasync.provider" |
| 481 | // Account type |
| 482 | public static final String ACCOUNT_TYPE = "com.example.android.datasync"; |
| 483 | // Account |
| 484 | public static final String ACCOUNT = "default_account"; |
| 485 | // Instance fields |
| 486 | Account mAccount; |
| 487 | ... |
| 488 | @Override |
| 489 | protected void onCreate(Bundle savedInstanceState) { |
| 490 | super.onCreate(savedInstanceState); |
| 491 | ... |
| 492 | /* |
| 493 | * Create the dummy account. The code for CreateSyncAccount |
| 494 | * is listed in the lesson Creating a Sync Adapter |
| 495 | */ |
| 496 | |
| 497 | mAccount = CreateSyncAccount(this); |
| 498 | ... |
| 499 | } |
| 500 | /** |
| 501 | * Respond to a button click by calling requestSync(). This is an |
| 502 | * asynchronous operation. |
| 503 | * |
| 504 | * This method is attached to the refresh button in the layout |
| 505 | * XML file |
| 506 | * |
| 507 | * @param v The View associated with the method call, |
| 508 | * in this case a Button |
| 509 | */ |
| 510 | public void onRefreshButtonClick(View v) { |
| 511 | ... |
| 512 | // Pass the settings flags by inserting them in a bundle |
| 513 | Bundle settingsBundle = new Bundle(); |
| 514 | settingsBundle.putBoolean( |
| 515 | ContentResolver.SYNC_EXTRAS_MANUAL, true); |
| 516 | settingsBundle.putBoolean( |
| 517 | ContentResolver.SYNC_EXTRAS_EXPEDITED, true); |
| 518 | /* |
| 519 | * Request the sync for the default account, authority, and |
| 520 | * manual sync settings |
| 521 | */ |
| 522 | ContentResolver.requestSync(mAccount, AUTHORITY, settingsBundle); |
| 523 | } |
| 524 | </pre> |