安卓同步适配器自动初始化同步

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个回答

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(...)意义重大,这意味着您的ContentProvider将进行ContentResolver.notifyChange(...)调用。为了使其正常工作,我遵循了开发指南中的做法,在用于SyncAdapter的每个URI中添加了CALLER_IS_SYNC_ADAPTER查询参数。请将此方法添加到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)

14

需要强调的是,似乎addPeriodicSync()需要setSyncAutomatically(),尽管文档表示setSyncAutomatically()仅用于检测网络闪烁。

请注意,如果时间间隔小于一分钟,则计划将被更正为大于60秒。


6

您需要将帐户默认设置为可同步:

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

我使用上述两行代码,它们正常运行。

添加ContentResolver.setSyncAutomatically(account, AUTHORITY, true);是我需要的,但似乎它并没有识别定期同步。当我添加帐户后,它只是不断地进行同步。 - Dandre Allison
请尝试使用新的Bundle()调用ContentResolver.addPeriodicSync()函数,而不是extras。 - Blehi
extras是一个新的Bundle(),我甚至尝试着不设置任何标志来使用它(Bundle extras = new Bundle(); addPeriodicSync(account, AUTHORITY, extras, 900);)。 - Dandre Allison
这有点晚了,但是这里的 AUTHORITY 是什么? - kapeels
1
我刚刚发现问题出在你的sync-adapter标签中的android:contentAuthority属性所对应的字符串上。 - kapeels

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接