【问题标题】:Syncadapter onPerformSync being called twice the first time第一次调用 Syncadapter onPerformSync 两次
【发布时间】:2014-01-14 18:14:42
【问题描述】:

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

这是我的“onCreate”中的代码,如果尚未创建帐户,则该代码会创建帐户并设置同步适配器。关于我做错了什么有什么想法吗?

    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”语句定期同步。

【问题讨论】:

  • 我遇到了几乎同样的问题。但是有一个提示:对于 Bundle arg,您可以只使用 new Bundle() 并去掉两行。
  • 您是否在此处检查了已接受答案的第 7 点? stackoverflow.com/questions/5253858/…

标签: android android-syncadapter


【解决方案1】:

我也观察到了这种行为。

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

澄清

但是,Zapek 关于 addPeriodic 同步或请求同步是“立即”同步的观察并不完全正确。两者都只是排队。此外,对于 addPeriodicSync(),以下内容成立:

这些定期同步遵循“自动同步”和 “masterSyncAutomatically”设置。虽然这些同步是预定的 在指定的频率,它可能需要更长的时间才能真正成为 如果其他同步在同步操作队列中领先于它,则启动。 这意味着实际开始时间可能会漂移。 (Documentation)

与您的问题有关

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

方法 addPeriodicSync() 不会禁用 setSyncAutomatically(), 因此您可能会在相对较短的时间内获得多次同步运行 时间。此外,在一个 调用 addPeriodicSync();不允许的标志是 addPeriodicSync() 的参考文档中描述。 Android Training Sync Adapter

Google 自己的解决方案看起来像你的,甚至频率更低(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);
}

【讨论】:

    【解决方案2】:

    除了 addPeriodicSync() 之外,您还请求同步吗?

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

    如果这没有帮助,您可以随时将上次同步的时间保存在首选项中,并检查每次同步的时间,这样您就可以将同步频率限制为您想要的任何值。

    希望有帮助!

    【讨论】:

    • 否 - 没有额外请求的同步。代码是“原样”。奇怪吧?我想我别无选择,只能按照你建议的方式实施。
    • 也许 addPeriodicSync() 会导致它不仅在指定的时间之后同步,而且马上同步?如果是这样,我想你仍然需要检查上次同步。
    【解决方案3】:

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

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

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

    除了确保在客户端和服务器之间没有数据更改的情况下优化同步以快速进行之外,您无能为力。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-19
      • 1970-01-01
      • 1970-01-01
      • 2021-03-04
      • 1970-01-01
      相关资源
      最近更新 更多