/** * A bound Service that instantiates the authenticator * when started. */ publicclassAuthenticatorServiceextendsService{ ... // Instance field that stores the authenticator object private Authenticator mAuthenticator; @Override publicvoidonCreate(){ // Create a new authenticator object mAuthenticator = new Authenticator(this); } /* * When the system binds to this Service to make the RPC call * return the authenticator's IBinder. */ @Override public IBinder onBind(Intent intent){ return mAuthenticator.getIBinder(); } }
/** * Handle the transfer of data between a server and an * app, using the Android sync adapter framework. */ publicclassSyncAdapterextendsAbstractThreadedSyncAdapter{ ... // Global variables // Define a variable to contain a content resolver instance ContentResolver mContentResolver; /** * Set up the sync adapter */ publicSyncAdapter(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 */ publicSyncAdapter( 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(); ... }
/* * 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. */ @Override publicvoidonPerformSync( Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult){ /* * Put the data transfer code here. */ ... }
package com.example.android.syncadapter; /** * Define a Service that returns an IBinder for the * sync adapter class, allowing the sync adapter framework to call * onPerformSync(). */ publicclassSyncServiceextendsService{ // Storage for an instance of the sync adapter privatestatic SyncAdapter sSyncAdapter = null; // Object to use as a thread-safe lock privatestaticfinal Object sSyncAdapterLock = new Object(); /* * Instantiate the sync adapter object. */ @Override publicvoidonCreate(){ /* * 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. * */ @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(); } }
publicclassMainActivityextendsFragmentActivity{ ... ... // Constants // The authority for the sync adapter's content provider publicstaticfinal String AUTHORITY = "com.example.android.datasync.provider"; // An account type, in the form of a domain name publicstaticfinal String ACCOUNT_TYPE = "example.com"; // The account name publicstaticfinal String ACCOUNT = "dummyaccount"; // Instance fields Account mAccount; ... @Override protectedvoidonCreate(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 */ publicstatic 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 <provider> 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. */ } } ... }
android:process=”:sync” tells the system to run the Service in a global shared process named sync,如果你有多个 sync adapter,他们可以共享这个 service, reduces overhead。
publicclassGcmBroadcastReceiverextendsBroadcastReceiver{ ... // Constants // Content provider authority publicstaticfinal String AUTHORITY = "com.example.android.datasync.provider" // Account type publicstaticfinal String ACCOUNT_TYPE = "com.example.android.datasync"; // Account publicstaticfinal String ACCOUNT = "default_account"; // Incoming Intent key for extended data publicstaticfinal String KEY_SYNC_REQUEST = "com.example.android.datasync.KEY_SYNC_REQUEST"; ... @Override publicvoidonReceive(Context context, Intent intent){ // Get a GCM object instance GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(context); // Get the type of GCM message String messageType = gcm.getMessageType(intent); /* * Test the message type and examine the message contents. * Since GCM is a general-purpose messaging system, you * may receive normal messages that don't require a sync * adapter run. * The following code tests for a a boolean flag indicating * that the message is requesting a transfer from the device. */ if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(messageType) && intent.getBooleanExtra(KEY_SYNC_REQUEST)) { /* * Signal the framework to run your sync adapter. Assume that * app initialization has already created the account. */ ContentResolver.requestSync(ACCOUNT, AUTHORITY, null); ... } ... } ... }
Run the Sync Adapter When Content Provider Data Changes
publicclassMainActivityextendsFragmentActivity{ ... // Constants // Content provider scheme publicstaticfinal String SCHEME = "content://"; // Content provider authority publicstaticfinal String AUTHORITY = "com.example.android.datasync.provider"; // Path for the content provider table publicstaticfinal String TABLE_PATH = "data_table"; // Account publicstaticfinal String ACCOUNT = "default_account"; // Global variables // A content URI for the content provider's data table Uri mUri; // A content resolver for accessing the provider ContentResolver mResolver; ... publicclassTableObserverextendsContentObserver{ /* * Define a method that's called when data in the * observed content provider changes. * This method signature is provided for compatibility with * older platforms. */ @Override publicvoidonChange(boolean selfChange){ /* * Invoke the method signature available as of * Android platform version 4.1, with a null URI. */ onChange(selfChange, null); } /* * Define a method that's called when data in the * observed content provider changes. */ @Override publicvoidonChange(boolean selfChange, Uri changeUri){ /* * Ask the framework to run your sync adapter. * To maintain backward compatibility, assume that * changeUri is null. */ ContentResolver.requestSync(ACCOUNT, AUTHORITY, null); } ... } ... @Override protectedvoidonCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); ... // Get the content resolver object for your app mResolver = getContentResolver(); // Construct a URI that points to the content provider data table mUri = new Uri.Builder() .scheme(SCHEME) .authority(AUTHORITY) .path(TABLE_PATH) .build(); /* * Create a content observer object. * Its code does not mutate the provider, so set * selfChange to "false" */ TableObserver observer = new TableObserver(false); /* * Register the observer for the data table. The table's path * and any of its subpaths trigger the observer. */ mResolver.registerContentObserver(mUri, true, observer); ... } ... }
publicclassMainActivityextendsFragmentActivity{ ... // Constants // Content provider authority publicstaticfinal String AUTHORITY = "com.example.android.datasync.provider" // Account type publicstaticfinal String ACCOUNT_TYPE = "com.example.android.datasync"; // Account publicstaticfinal String ACCOUNT = "default_account"; // Instance fields Account mAccount; ... @Override protectedvoidonCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); ... /* * Create the dummy account. The code for CreateSyncAccount * is listed in the lesson Creating a Sync Adapter */
mAccount = CreateSyncAccount(this); ... } /** * Respond to a button click by calling requestSync(). This is an * asynchronous operation. * * This method is attached to the refresh button in the layout * XML file * * @param v The View associated with the method call, * in this case a Button */ publicvoidonRefreshButtonClick(View v){ ... // Pass the settings flags by inserting them in a bundle Bundle settingsBundle = new Bundle(); settingsBundle.putBoolean( ContentResolver.SYNC_EXTRAS_MANUAL, true); settingsBundle.putBoolean( ContentResolver.SYNC_EXTRAS_EXPEDITED, true); /* * Request the sync for the default account, authority, and * manual sync settings */ ContentResolver.requestSync(mAccount, AUTHORITY, settingsBundle); }