Android SyncAdapter автоматически инициализирует синхронизацию

У меня есть 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());
}

Я могу добавить учетную запись в диспетчер аккаунта с помощью настроек, но мне также нужно вручную включить синхронизацию для учетной записи в настройках, даже если фоновые данные и автоматические настройки синхронизации включены в эмуляторе. Если я вручную включу синхронизацию, то синхронизация выполняется нормально, она просто не запускается по умолчанию.

Ответы

Ответ 1

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

Как Blehi сказал, что будет инициировать автоматическую синхронизацию данной учетной записи, учитывая глобальные настройки, включены "Фоновые данные" и "Автосинхронизация".

Чтобы предотвратить синхронизацию "back-to-back" (от jcwenger), убедитесь, что если какой-либо метод в SyncAdapter.onPerformSync(...) вызывает ContentResolver.notifyChange(...) он использует ContentResolver.notifyChange(uri, observer, false), чтобы отметить уведомление, чтобы не запускать вызов синхронизации (третий параметр syncToNetwork).

Если вы используете ContentProvider для выполнения вставок/удалений/обновлений для вас SyncAdapter, имеет смысл вызвать ContentResolver.notifyChange(...), чтобы при видимости приложения пользователь мог получать обновления от SyncAdapter, что означает, что у вас будет ContentProvider выполнение ContentResolver.notifyChange(...) вызовов. Чтобы настроить этот набор на работу, я добавил (после руководство разработчика) CALLER_IS_SYNC_ADAPTER параметр запроса для каждый URI, который используется для 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)

Ответ 2

Чтобы подчеркнуть, кажется, что addPeriodicSync() требует setSyncAutomatically(), хотя в документации указано, что setSyncAutomatically() предназначен только для обнаружения сетевых щекоток.

Обратите внимание, что период будет скорректирован до > 60 с, если он меньше минуты.

Ответ 3

По умолчанию вы должны установить синхронизацию:

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

Я использую вышеуказанные 2 строки и работает нормально.

Ответ 4

Сначала создайте учетную запись и проверьте поддержку синхронизации для нее с помощью 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);
}

Затем вы можете запускать синхронизацию в любое время. Он будет срабатывать.

Примечание: onPerformSync() для setSyncAutomatically() будет вызываться первым, тогда будет инициирован только другой запрос синхронизации. Но для принудительной синхронизации просто добавьте еще 2 дополнительных флага.

Bundle bundle= new Bundle();
    bundle.putBoolean(
            ContentResolver.SYNC_EXTRAS_MANUAL, true);
    bundle.putBoolean(
            ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
    ContentResolver.requestSync(account, AUTHORITY, bundle);