Android订购了同步

时间:2014-08-09 09:12:46

标签: android synchronization android-contentprovider android-syncadapter

我正在调查如何以精确的顺​​序调用同步适配器。

事实上,我有几个供应商,如客户和合同。 同步其中一种方式:

  1. 向服务器发送本地修改以更新其数据库(例如新客户端,更新的合同等)
  2. 接收服务器修改并更新本地数据库
  3. 所以,我必须同步客户端和那些同步合同。实际上,如果我首先开始同步合同,其中一个可以引用尚未同步并插入智能手机数据库的客户端。

    在进行了一些测试之后,我发现不同提供商的同步请求是同时执行的。 例如,调用:

    ContentResolver.requestSync(account, ClientsProvider.AUTHORITY, syncBundle);
    ContentResolver.requestSync(account, ContractsProvider.AUTHORITY, syncBundle);
    

    将导致客户端和合同的并行(因此,无序)同步。

    有人知道如何一个接一个地执行同步请求或者有解决此问题的想法吗?

1 个答案:

答案 0 :(得分:0)

到目前为止,我找到的唯一解决方案是使用服务以及wait()notify()方法,以便服务在同步调用之间暂停。

如果我有两个名为ClientsProviderContractsProvider的提供商,我创建并声明了2个SyncAdapter,每个都有以下onPerformSync()方法:

@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()是我放置同步逻辑的方法。唯一的区别是需要调用MySyncService.releaseLock()才能告诉服务同步已完成:

public void performSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult)
{
    try
    {
        // Sync logic goes there
    }
    finally
    {
        MySyncService.releaseLock();
    }
}

服务代码是:

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;
                }
            }
        }
    }
}