Как реализовать учетную запись на Android без адаптера синхронизации

Я внедряю систему входа для приложения Android, используя встроенную систему учетных записей (с API-интерфейсами AccountManager).

Все хорошо и хорошо на Android 2.2+, но на Android 2.1 не включая SyncAdapter вызывает перезагрузки на экране настроек учетной записи (см. http://code.google.com/p/android/issues/detail?id=5009 и AccountManager без адаптера синхронизации?)

Чтобы обойти это, я реализовал заглушку SyncAdapter, которая просто возвращает null из IBinder onBind(Intent intent), и добавила соответствующие материалы в манифест. Это устраняет проблему перезагрузки на Android 2.1.

Однако это еще одна проблема: после добавления учетной записи система Android, спустя некоторое время, инициирует синхронизацию учетной записи. Хотя ошибок нет (действительно, мой SyncAdapter ничего не делает, он не имеет возможности вызывать ошибки, если не возвращая null), значок синхронизации остается на панели уведомлений вверху. Это приводит к тому, что система синхронизации Android поддерживает постоянную блокировку слежения, не позволяя устройству спать.

Учетная запись не отображает никаких синхронизируемых компонентов на экране настроек учетной записи (в заголовке "Данные и синхронизация" ) и всегда отображает "Синхронизация отключена" для статуса синхронизации в списке учетных записей (даже если значок синхронизации отображается в панели уведомлений). Отключение синхронизации учетных записей не устраняет проблему. Удаление учетной записи останавливает проблему.

Мое предположение: я не должен возвращать null. Должен ли я возвращать базовую реализацию ThreadedSyncAdapter? Любая помощь в получении системы учетных записей без соответствующей синхронизации, работающей правильно на 2.1 и 2.2+, очень ценится.

Ответ 1

Я решил проблему самостоятельно: вы не можете вернуть null из метода onBind своей службы - вы должны вернуть IBinder AbstractThreadedSyncAdapter.

Это имеет нежелательный эффект добавления записи в раздел "Данные и синхронизация" на странице настроек учетной записи, хотя моя реализация AbstractThreadedSyncAdapter ничего не делает; Я надеялся избежать этого.

Подводя итог, чтобы использовать систему учетных записей в Android, вы должны:

  • Внедрить службу с IntentFilter для android.content.SyncAdapter.
  • Эта служба должна вернуть IBinder реализации AbstractThreadedSyncAdapter из нее onBind.
  • Это требует, чтобы у вас был ContentProvider (может быть просто реализация заглушки), который называется contentAuthority в XML файле SyncAdapter.
  • Это означает, что ваш ContentProvider указан в заголовке "Данные и синхронизация" на странице настроек вашей учетной записи.

Ответ 2

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

Лучший способ справиться с этим, что требует минимального кода и фактически делает его так, что учетная запись никогда не синхронизируется, если специально не вызвана для синхронизации в коде:

ContentResolver.setIsSyncable(account, ContactsContract.AUTHORITY, 0);

Теперь это требует, чтобы в момент создания вашей учетной записи вы вызываете этот статический метод. Принимая во внимание, что первым параметром является учетная запись для установки этого параметра, второй параметр является используемым полномочием contentprovider, а третий является целым числом, которое при установке на положительное число позволяет синхронизировать, когда установлено значение 0, отключает синхронизацию и когда установлено что-либо еще делает его неизвестным. Полномочия на использование можно найти внутри вашего "sync_something.xml" в атрибуте contentAuthority, который используется вашим SyncAdapter:

<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
android:contentAuthority="com.android.contacts" 
android:accountType="com.myapp.account"/> <!-- This being your own account type-->

Указанный выше XML файл указан внутри служебной части вашего AndroidManifest.xml:

<service android:name=".DummySyncAdapterService"
        exported="true"
        android:process=":contacts">
        <intent-filter>
            <action android:name="android.content.SyncAdapter" />
        </intent-filter>
        <meta-data android:name="android.content.SyncAdapter" 
            android:resource="@xml/sync_something" /> <!--This points to your SyncAdapter XML-->
    </service>

Это фрагмент кода, который я использую для создания моей учетной записи в моей учетной записи LoginActivity:

Account account = new Account("John Doe", "com.myapp.account");
ContentResolver.setIsSyncable(account, ContactsContract.AUTHORITY, 0);
AccountManager am = AccountManager.get(LoginActivity.this);
boolean accountCreated = am.addAccountExplicitly(account, "Password", null);
Bundle extras = LoginActivity.this.getIntent().getExtras();
if(extras != null){
    if (accountCreated) { 
        AccountAuthenticatorResponse response = extras.getParcelable(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE);
        Bundle result = new Bundle();
        result.putString(AccountManager.KEY_ACCOUNT_NAME, "John Doe");
        result.putString(AccountManager.KEY_ACCOUNT_TYPE, "com.myapp.account");
        response.onResult(result);
    }
}

Большая часть этого заключается в том, что, когда система пытается синхронизировать службу, она проверяет, если служба сначала синхронизируется, если она установлена ​​в false, она отменяет синхронизацию. Теперь вам не нужно создавать свой собственный ContentProvider, а ваш ContentProvider не отображается в разделе "Данные и синхронизация". Однако вам нужно иметь реализацию заглушки AbstractThreadedSyncAdapter, которая возвращает IBinder внутри метода onBind. И последнее, но не менее важное: это делает так, что пользователь не может включить синхронизацию или использовать "Sync Now" для этой учетной записи, если вы не добавили функциональность внутри своего приложения.