15

我有一个SyncAdapter我的应用程序,以及一个AccountManager将我的应用程序帐户添加到 Android 帐户管理器。当我将帐户添加到客户经理时,我的代码如下所示:

Bundle data = new Bundle(5);
data.putString(_PEOPLE_ID, people_id);
data.putString(_FIRST_NAME, first_name);
data.putString(_LAST_NAME, last_name);
data.putString(_PLAN, plan);
data.putString(_BIRTHDAY, birthday);
Account account = new Account(username, _ACCOUNT_TYPE);
try {
    boolean created;
    created = _account_manager.addAccountExplicitly(account,
                                   _cryptography.encrypt(_SEED, password), data);
    response.accountCreated(created);
    _account_manager.setAuthToken(account, _TOKEN_TYPE, session_token);
    _model.updateActiveAccount(people_id, username, password);
    SharedPreferences.Editor settings = _settings.edit();
    settings.putString(_ACCOUNT_TYPE, account.name);
    settings.putString(_TOKEN_TYPE, session_token);
    settings.commit();
    // Tells the content provider that it can sync this account
    ContentResolver.setIsSyncable(account, AUTHORITY, 1);
    final Bundle extras = new Bundle(1);
    extras.putBoolean(SYNC_EXTRAS_INITIALIZE, true);
    ContentResolver.addPeriodicSync(account, AUTHORITY, extras, 900);
} catch (Exception e) {
    Ln.e(e.getCause());
}

我可以通过设置成功将帐户添加到帐户管理器,但我还必须在设置中手动为帐户启用同步,即使在模拟器上启用了后台数据和自动同步设置。如果我手动启用同步,则同步执行良好,只是默认情况下不会启动。

4

4 回答 4

30
ContentResolver.setIsSyncable(account, AUTHORITY, 1);
ContentResolver.setSyncAutomatically(account, AUTHORITY, true);

正如Blehi所说,将启动给定帐户的自动同步,给定全局设置,启用“后台数据”和“自动同步”。

为了防止背靠背同步(来自 jcwenger),请确保 SyncAdapter.onPerformSync(...)调用中的任何方法ContentResolver.notifyChange(...)用于ContentResolver.notifyChange(uri, observer, false)标记通知不触发同步调用(第三个参数是syncToNetwork)。

如果您使用 为ContentProvider您执行插入/删除/更新,那么SyncAdapter调用是有意义的,ContentResolver.notifyChange(...)这样当应用程序可见时,用户可以从 接收更新SyncAdapter,这意味着您将ContentProvider进行ContentResolver.notifyChange(...)调用。为了让这个设置正常工作,我添加了(按照开发指南CALLER_IS_SYNC_ADAPTER查询参数到每个用于SyncAdapter. 将此方法添加到ContentProvider以测试传入的 URI

/**
 * Determines if the given URI specifies that the request is coming from the sync adapter.
 * @param uri the given URI
 * @return true if the uri specifies that the request is coming from the sync adapter
 */
private boolean callerIsSyncAdapter(Uri uri) {
    final String is_sync_adapter = uri.getQueryParameter(CALLER_IS_SYNC_ADAPTER);
    return is_sync_adapter != null && !is_sync_adapter.equals("0");
}  

那么你可以做

getContext().getContentResolver().notifyChange(uri, observer, !callerIsSyncAdapter(uri));

每当您需要发送更改通知时。

如果您想安排以一定频率定期执行同步(轮询服务器),请将其添加到ContentResolver.setSyncAutomatically(...)调用中。

ContentResolver.addPeriodicSync(account, AUTHORITY, new Bundle(), frequency_in_seconds)
于 2012-06-19T18:24:48.227 回答
14

只是为了强调,似乎 addPeriodicSync()需要setSyncAutomatically(),即使文档说 setSyncAutomatically() 仅用于检测网络痒痒。

请注意,如果少于一分钟,则该周期将被更正为 >60 秒。

于 2013-12-05T11:38:26.430 回答
6

您必须将帐户设置为默认可同步:

ContentResolver.setIsSyncable(account, AUTHORITY, 1);
ContentResolver.setSyncAutomatically(account, AUTHORITY, true);

我使用上述 2 行,它工作正常。

于 2012-06-18T20:52:46.910 回答
2

最初创建一个帐户并使用 AccountManager 检查同步支持。如果帐户支持同步,则调用 setIsSyncable() 和 setSyncAutomatically()。

AccountManager accountManager = (AccountManager) this.getSystemService(ACCOUNT_SERVICE);
if(accountManager.addAccountExplicitly(newAccount, null, null)){
         ContentResolver.setIsSyncable(account, AUTHORITY, 1);
         ContentResolver.setSyncAutomatically(account, AUTHORITY, true);
}

然后您可以随时触发同步。它会触发。

注意: setSyncAutomatically() 的 onPerformSync() 将首先被调用,然后才会触发其他同步请求。但是要进行强制同步,只需添加 2 个额外的标志。

Bundle bundle= new Bundle();
    bundle.putBoolean(
            ContentResolver.SYNC_EXTRAS_MANUAL, true);
    bundle.putBoolean(
            ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
    ContentResolver.requestSync(account, AUTHORITY, bundle);
于 2015-06-23T11:45:53.933 回答