Syncadapter onPerformSync第一次被调用两次

时间:2012-08-20 19:49:27

标签: android android-syncadapter

我的syncadapter效果很好,除了一件事。用户安装应用程序后,我的应用程序会同步两次。稍后,如果我在“设置”中手动同步它,它只会按预期同步一次。这只是应用程序的第一次运行。

这是我的“onCreate”中的代码,如果尚未创建帐户,则创建帐户并设置syncadapter。关于我做错了什么想法?

    if (accountManager.addAccountExplicitly(appAccount, null, null)) {
       ContentResolver.setIsSyncable(appAccount, PROVIDER, 1);
       ContentResolver.setSyncAutomatically(appAccount, PROVIDER, true);

       Bundle extras = new Bundle();
       extras.putBoolean("dummy stuff", true);
       ContentResolver.addPeriodicSync(appAccount, PROVIDER, extras, 43200);
    }

我希望的行为是让应用程序在安装后立即同步一次,然后根据“addPeriodicSync”语句定期进行同步。

3 个答案:

答案 0 :(得分:4)

我也观察到了这种行为。

这是正确的,addAccountExplicit()将触发过时帐户的系统范围帐户重新同步。

Clarificiation

然而,Zapek关于addPeriodic同步或请求同步是“立即”同步的观察结果并不完全正确。两者都排队等候。此外,以下适用于addPeriodicSync():

  

这些定期同步尊重“syncAutomatically”和   “masterSyncAutomatically”设置。虽然这些同步是预定的   在指定的频率,实际可能需要更长的时间   如果在同步操作队列中其他同步位于其前面,则启动。   这意味着实际的开始时间可能会漂移。   (Documentation

与您的问题有关

在运行同步适配器的培训中描述了您的体验:

  

方法addPeriodicSync()不会禁用setSyncAutomatically(),   所以你可以在相对较短的时间内获得多个同步运行   时间。此外,a中只允许使用几个同步适配器控制标志   调用addPeriodicSync();不允许的标志是   在addPeriodicSync()的引用文档中描述。   Android Training Sync Adapter

谷歌自己的解决方案与您的解决方案相似,频率更低(60 * 60 = 3600):

    if (accountManager.addAccountExplicitly(account, null, null)) {
        // Inform the system that this account supports sync
        ContentResolver.setIsSyncable(account, CONTENT_AUTHORITY, 1);
        // Inform the system that this account is eligible for auto sync when the network is up
        ContentResolver.setSyncAutomatically(account, CONTENT_AUTHORITY, true);
        // Recommend a schedule for automatic synchronization. The system may modify this based
        // on other scheduled syncs and network utilization.
        ContentResolver.addPeriodicSync(
                account, CONTENT_AUTHORITY, new Bundle(),SYNC_FREQUENCY);
        newAccount = true;
    }

命题

我建议使用onPerformSync()中的SyncStats实际将有关初始同步的一些信息返回给系统,以便更有效地安排。

syncResult.stats.numEntries++; // For every dataset

如果已经安排了其他任务,这可能无济于事 - 调查

此外,可以设置一个标志'isInitialOnPerformSync'(w.sharedPreferences),以使其他任务备份。

syncResult.delayUntil = <time>;

我个人并不喜欢在初始同步后创建固定的无同步时间帧。

进一步考虑 - 立即初始同步

如澄清中所述,同步不会立即与您的设置一起运行。有一个解决方案,可让您立即同步。这不会影响同步设置,也不会导致它们退避,这就是为什么这不能解决您的问题,但它会导致您的用户无需等待同步启动。重要的是,如果您使用此功能以这种方式在您的应用中显示主要内容。

代码: 在正常的应用程序进程中设置 isInitialSync 的标记(例如,您可以在defaultSharedPreferences中保存)。您甚至可以使用在初始完成安装或登录时(如果需要验证),您可以调用立即同步,如下所示。

/**
 * Start an asynchronous sync operation immediately. </br>
 *
 * @param account
 */
public static void requestSyncImmediately(Account account) {
     // Disable sync backoff and ignore sync preferences. In other words...perform sync NOW!
    Bundle settingsBundle = new Bundle();
    settingsBundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
    settingsBundle.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
    // Request sync with settings
    ContentResolver.requestSync(account, SyncConstants.CONTENT_AUTHORITY, settingsBundle);
}

答案 1 :(得分:2)

您是否要求同步除addPeriodicSync()?

首次添加帐户时,它应自行同步。因此,任何额外的同步请求都会导致双重同步。

如果这没有帮助,您可以随时在偏好设置中保存上次同步的时间并检查每次同步,以便您可以将同步频率限制为您想要的任何频率。

希望有所帮助!

答案 2 :(得分:1)

addAccountExplicitely()导致具有未知可同步状态的所有帐户的同步(包括您新添加的SyncAdapter)。

问题是执行时间可能需要几秒到几分钟,具体取决于安装了SyncAdapter和配置帐户的其他应用程序的数量。

addPeriodicSync()(或requestSync())将立即执行同步,这在用户需要在启动应用程序时尽快查看数据时是理想的。

除了确保在客户端和服务器之间没有数据发生变化的情况下快速优化同步时,您无能为力。