2016年2月27日 星期六

Android SyncManager and SyncAdapters

Why SyncManager and SyncAdapters?

Send More at one time and send less frequency

if send little each time and send more time ,will use more power.

SyncManager and SyncAdapters
Tutorial:
what does it do?

it is because the SyncManager and SyncAdapters is control by the system,we don’t onpen the app,iot still update
now,we try to use the SyncManager and SyncAdaptersto for the weather app

Implementing a Sync Adapter

SyncAdapters and Sunshine

Throughout this course you’ve been learning about different ways to handle Sunshine’s need to do data processing and network calls off of the main thread. For the network call to the Open Weather Map API, the best solution is to use a SyncAdapter. Why? Well SyncAdapters are meant to keep local data on the device in sync with data on the web. This is exactly what we’re doing with Open Weather Map. We’re storing a local cache of weather data from Open Weather Map, with the goal of fast load times, offline functionality and not necessitating a network call every time we load an activity.
Additionally, using a Sync Adapter will intelligently maintain a balance between keeping our local weather data cache up to date and saving the battery by being smart about when to place network calls.
Many of the normal use cases for sync adapters involve syncing the app's local data with information from an online account. For example, in an email app, a sync adapter might be used to pull down a user’s emails at regular intervals. Of course to do this the email app would need to store the user’s account information, such as a username and password, so that the app could log in and grab the new messages. To manage this, sync adapters each have a concept of a user’s account, tied with the sync adapter.
Does Open Weather Map need a user account? No. But we still need to implement the classes to handle accounts.

Instructions

1. Copy over the sync package
You can copy this package from here. Put it on the same level as your data package. This package includes the following classes:
Sync Folder
  • SunshineAuthenticator - This extends AbstractAccountAuthenticator. This code manages authenticatingwith Sunshine’s background service (as in Open Weather Map). Since Open Weather Map needs no authentication, this is literally the stub code from the Developer Guide on sync adapters.
  • SunshineAuthenticatorService - This will allow the framework to access our SunshineAuthenticator. This is also almost exactly the same as the stub code from the Developer Guide on sync adapters.
  • SunshineSyncService - This service provides framework access to your SunshineSyncAdapter. This too is almost exactly the same as the stub code from the Developer Guide on sync adapters.
  • SunshineSyncAdapter - This is the actual sync adapter; it extends AbstractThreadedSyncAdapter. Note the following methods:
    • onPerformSync - This is the important method which is overridden when you subclass AbstractThreadedSyncAdapter. This is what happens when a sync occurs. In our case, we’ll eventually want to move the network code here.
    • getSyncAccount() - This is a helper method we’ve coded for you. Whenever you request a sync, you need a sync account. This is in case requesting the sync requires a login (in our situation, the Open Weather API doesn’t, but we still have our dummy account). This method gives us one of our dummy accounts.
    • syncImmediately() - This is a helper method we’ve coded for you. It tells the system to perform a sync with our sync adapter immediately.
2. Add the following two xml files to the res/xml folder
You can copy these files from here. This includes:
  • authenticator.xml - This resource file plugs your authenticator into your sync adapter and account frameworks by providing it with some of the meta data it needs.
  • syncadapter.xml - This resource file defines the settings associated with your SyncAdapter.
3. Update your strings.xml and AndroidManifest
  • Add the following gist to the strings.xml.
  • Note: Make sure all references to content_authority match the string you define here. The string sync_account_type suggests that the account is specific to our SunshineApp. The content_authority string is the Uri authority for your content provider.
We’re going to make four changes to our AndroidManifest.xml.
  • Change 1 - Add our new SunshineAuthenticator and SunshineAuthenticatorService classes to the AndroidManifest.xml.
  • Change 2 - We’re going to attach our WeatherProvider to the SyncAdapter. Change the provider tag for WeatherProvider in the AndroidManifest to the code in the Gist below.
  • Code to replace provider tag in AndroidManifest.xml:
  • android:exported="false" means that only our app can see our content provider.
  • android:syncable="true" mean that this content provider will be synced with a server.
  • Note how we now use the strings.xml content_authority to signify our content_authority.
  • Change 3 - Add additional permissions at the start of AndroidManifest.xml.
  • Change 4 - Finally, register the SunshineSyncService in the AndroidManifest.xml.
4. Test that it works
At this point you can test if everything is working properly:
  1. In the SunshineSyncAdapter’s onPerformSync method, add a Log statement.
  2. Comment out other code in the updateWeather function in ForecastFragment and replace it with a call to the syncImmediately helper function.
  3. Run your app and verify that the Log statement in onPerformSync prints to the console when you Refresh.
  4. You can also go into your phone’s Settings and see that the dummy Sunshine account is now there.
Sync Folder
Finishing the Sync Adapter
  • Make sure that updateWeather in ForecastFragment starts a sync.
  • Move the synchronization code from onHandleIntent in SunshineService to onPerformSync and fix any errors.
  • Make onPerformSync directly access the preference for location.
Hint : You already have a helper method in SunshineSyncAdapter that will run a sync.
Scheduled Synchronization


Here you will be creating the logic to, when you start the app, check if an account has been created for Sunshine and if not, create a new account and configure a periodic sync to start.

Instructions

1. Cleaning up the Code
  • If you haven’t already, delete FetchWeatherTask and the SunshineService. They are now just older, unused classes which do the same thing that the SunshineSyncAdapter class is doing.
  • Clean up the AndroidManifest.xml and remove SunshineService and the AlarmReceiver from the xml.
  • In onPreferenceChange in the SettingsActivity, call syncImmediately() instead of creating and executing a FetchWeatherTask.
2. Add and update methods in SunshineSyncAdapter
Add the following methods which can be found in this gist.
  • configurePeriodicSync
  • onAccountCreated
  • initializeAdapter
Also add the line onAccountCreated() to the method getSyncAccount after you find that a new account has been created. You can copy and replace using the method from this gist
3. Add Constants for Sync Time
At the top of SunshineSyncAdapter add the following constants for sync time. Devices capable of doing flexible syncs will sync more often.
// Interval at which to sync with the weather, in milliseconds.
// 60 seconds (1 minute) * 180 = 3 hours
public static final int SYNC_INTERVAL = 60 * 180;
public static final int SYNC_FLEXTIME = SYNC_INTERVAL/3;
4. Start everything in MainActivity
Go to MainActivity. At the end of MainActivity call: SunshineSyncAdapter.initializeSyncAdapter(this);

The control flow

  1. Your MainActivity is created and the sync adapter is initialized.
  2. During initialization, getSyncAccount is called.
  3. getSyncAccount will create a new account if no sunshine.example.com account exists. If this is the case,onAccountCreated will be called.
  4. onAccountCreated configures the periodic sync and calls for an immediate sync. At this point, Sunshine will sync with the Open Weather API either every 3 hours (if the build version is less than KitKat) or everyone 1 hour (if the build version is greater than or equal to KitKat)

Test if it Works

If you'd like to quickly test that your periodic sync code is working:
  1. Change the SYNC_INTERVAL time; set it to something low, for example, 30 seconds.
  2. Add a Log statement in onPerformSync
  3. Uninstall Sunshine or remove the Sunshine account.
  4. Finally run Sunshine again and confirm syncs are being called. You will want to undo these changes and uninstall Sunshine again when done so that your phone is not syncing every 30 seconds.
Move onwards for a quick quiz...

here is the finished app: