Data Synchronization with Sync Adapter
Dummy Sync Adapter with Stub Provider
Section titled “Dummy Sync Adapter with Stub Provider”/** * Define a sync adapter for the app. * <p/> * <p>This class is instantiated in {@link SyncService}, which also binds SyncAdapter to the system. * SyncAdapter should only be initialized in SyncService, never anywhere else. * <p/> * <p>The system calls onPerformSync() via an RPC call through the IBinder object supplied by * SyncService. */class SyncAdapter extends AbstractThreadedSyncAdapter { /** * Constructor. Obtains handle to content resolver for later use. */ public SyncAdapter(Context context, boolean autoInitialize) { super(context, autoInitialize); }
/** * Constructor. Obtains handle to content resolver for later use. */ public SyncAdapter(Context context, boolean autoInitialize, boolean allowParallelSyncs) { super(context, autoInitialize, allowParallelSyncs); }
@Override public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) { //Jobs you want to perform in background. Log.e("" + account.name, "Sync Start"); }
}/** * Define a Service that returns an 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. */ @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. */ @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(); }}public class Authenticator extends AbstractAccountAuthenticator { // Simple constructor public Authenticator(Context context) { super(context); }
// Editing properties is not supported @Override public Bundle editProperties( AccountAuthenticatorResponse r, String s) { throw new UnsupportedOperationException(); }
// Don't add additional accounts @Override public Bundle addAccount( AccountAuthenticatorResponse r, String s, String s2, String[] strings, Bundle bundle) throws NetworkErrorException { return null; }
// Ignore attempts to confirm credentials @Override public Bundle confirmCredentials( AccountAuthenticatorResponse r, Account account, Bundle bundle) throws NetworkErrorException { return null; }
// Getting an authentication token is not supported @Override public Bundle getAuthToken( AccountAuthenticatorResponse r, Account account, String s, Bundle bundle) throws NetworkErrorException { throw new UnsupportedOperationException(); }
// Getting a label for the auth token is not supported @Override public String getAuthTokenLabel(String s) { throw new UnsupportedOperationException(); }
// Updating user credentials is not supported @Override public Bundle updateCredentials( AccountAuthenticatorResponse r, Account account, String s, Bundle bundle) throws NetworkErrorException { throw new UnsupportedOperationException(); }
// Checking features for the account is not supported @Override public Bundle hasFeatures( AccountAuthenticatorResponse r, Account account, String[] strings) throws NetworkErrorException { throw new UnsupportedOperationException(); }}/** * A bound Service that instantiates the authenticator * when started. */public class AuthenticatorService extends Service { // Instance field that stores the authenticator object private Authenticator mAuthenticator; @Override public void onCreate() { // 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(); }}<uses-permission android:name="android.permission.GET_ACCOUNTS" /><uses-permission android:name="android.permission.READ_SYNC_SETTINGS" /><uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" /><uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
<service android:name=".syncAdapter.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>
<service android:name=".authenticator.AuthenticatorService"> <intent-filter> <action android:name="android.accounts.AccountAuthenticator" /> </intent-filter> <meta-data android:name="android.accounts.AccountAuthenticator" android:resource="@xml/authenticator" /> </service>
<provider android:name=".provider.StubProvider" android:authorities="com.yourpackage.provider" android:exported="false" android:syncable="true" /><?xml version="1.0" encoding="utf-8"?><account-authenticator xmlns:android="http://schemas.android.com/apk/res/android" android:accountType="com.yourpackage" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:smallIcon="@mipmap/ic_launcher" /><?xml version="1.0" encoding="utf-8"?><sync-adapter xmlns:android="http://schemas.android.com/apk/res/android" android:accountType="com.yourpackage.android" android:allowParallelSyncs="false" android:contentAuthority="com.yourpackage.provider" android:isAlwaysSyncable="true" android:supportsUploading="false" android:userVisible="false" />/* * Define an implementation of ContentProvider that stubs out * all methods */public class StubProvider extends ContentProvider { /* * Always return true, indicating that the * provider loaded correctly. */ @Override public boolean onCreate() { return true; }
/* * Return no type for MIME type */ @Override public String getType(Uri uri) { return null; }
/* * query() always returns no results * */ @Override public Cursor query( Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { return null; }
/* * insert() always returns null (no URI) */ @Override public Uri insert(Uri uri, ContentValues values) { return null; }
/* * delete() always returns "no rows affected" (0) */ @Override public int delete(Uri uri, String selection, String[] selectionArgs) { return 0; }
/* * update() always returns "no rows affected" (0) */ public int update( Uri uri, ContentValues values, String selection, String[] selectionArgs) { return 0; }} public Account CreateSyncAccount(Context context, String accountName) { // Create the account type and default account Account newAccount = new Account( accountName, "com.yourpackage"); // 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. */ } return newAccount; }Bundle bundle = new Bundle();bundle.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);bundle.putBoolean(ContentResolver.SYNC_EXTRAS_FORCE, true);bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);ContentResolver.requestSync(null, MyContentProvider.getAuthority(), bundle);