The only solution I have found so far is to use a service and the wait()
and notify()
methods in order for the service to pause between sync calls.
If I have 2 providers named ClientsProvider
and ContractsProvider
, I create and declare 2 SyncAdapters, each one having the following onPerformSync()
method:
@Override
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult)
{
boolean callerIsMySyncService = extras.getBoolean(GlobalDataSyncService.EXTRA_CALLER_IS_MY_SYNC_ADAPTER, false);
if (callerIsMySyncService)
{
performSync(account, extras, authority, provider, syncResult);
}
else
{
Intent intent = new Intent(context, MySyncService.class);
intent.putExtra(MySyncService.EXTRA_ACCOUNT, account);
context.startService(intent);
}
}
performSync()
is the method where I put my sync logic. The only difference is the need to call MySyncService.releaseLock()
in order to tell the service that sync is finished:
public void performSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult)
{
try
{
// Sync logic goes there
}
finally
{
MySyncService.releaseLock();
}
}
The service code is:
public class MySyncService extends Service
{
public static String EXTRA_CALLER_IS_MY_SYNC_ADAPTER = "isCaller";
public static String EXTRA_ACCOUNT = "account";
private static Boolean isSyncing = Boolean.FALSE;
private static Object lock = new Object();
public MySyncService() {}
@Override
public int onStartCommand(Intent intent, int flags, int startId)
{
synchronized (isSyncing) {
Account account = (Account)intent.getParcelableExtra(EXTRA_ACCOUNT);
// Sync only if it not already in progress and if there is an account
if ( ! isSyncing && account != null)
{
isSyncing = Boolean.TRUE;
new Thread(new SyncRunner(account)).start();
}
}
return START_REDELIVER_INTENT;
}
public static void releaseLock()
{
synchronized (lock) {
try
{
lock.notify();
}
catch (IllegalMonitorStateException e)
{
// Log error
}
}
}
@Override
public IBinder onBind(Intent intent)
{
throw new UnsupportedOperationException("Not yet implemented");
}
class SyncRunner implements Runnable
{
private Account account;
public SyncRunner(Account account)
{
this.account = account;
}
public void run()
{
try
{
Bundle syncBundle = new Bundle();
syncBundle.putBoolean(EXTRA_CALLER_IS_MY_SYNC_ADAPTER, true);
ContentResolver.requestSync(account, ClientsProvider.AUTHORITY, syncBundle);
synchronized (lock) {
lock.wait();
}
ContentResolver.requestSync(account, ContractsProvider.AUTHORITY, syncBundle);
synchronized (lock) {
lock.wait();
}
}
catch (InterruptedException e)
{
// Log error
}
finally
{
synchronized (isSyncing) {
isSyncing = Boolean.FALSE;
}
}
}
}
}