¿Cómo implemento una cuenta en Android sin un syncAdapter?
Pregunta
Estoy implementando un sistema de inicio de sesión para una aplicación Android que utiliza el sistema de cuentas incorporado (con las API de AccountManager).
Todo está bien en Android 2.2+, pero en Android 2.1 sin incluir un SyncAdapter causa reinicios en la pantalla de configuración de la cuenta (ver http://code.google.com/p/android/issues/detail?id=5009 y AccountManager sin un SyncAdapter?)
Para evitar esto, implementé un syncAdapter, que solo devuelve null
de IBinder onBind(Intent intent)
, y agregó las cosas relevantes al manifiesto. Esto resuelve el problema de reinicio en Android 2.1.
Sin embargo, introduce un problema adicional: después de agregar una cuenta, el sistema Android, algún tiempo después, iniciará una sincronización de cuenta. Aunque no ocurren errores (de hecho, mi syncAdapter no hace nada, no tiene forma de causar errores a menos que regrese null
), el icono de sincronización permanece atascado en la barra de notificaciones en la parte superior. Esto da como resultado que el sistema de sincronización de Android mantenga un Lock de estela permanente, evitando que el dispositivo duerma.
La cuenta no enumera ningún componente sincronizable en la pantalla de configuración de la cuenta (en el encabezado de 'datos y sincronización'), y siempre muestra 'sincronización' para el estado de sincronización en la lista de cuentas (incluso mientras el icono de sincronización es visible en La barra de notificaciones). Desactivar la sincronización de la cuenta no elimina el problema. Eliminar la cuenta detiene el problema.
Supongo que no debería regresar nulo. ¿Debería devolver una implementación básica de ThreadedSynCadapter? Cualquier ayuda para obtener un sistema de cuenta sin una sincronización asociada que funcione correctamente en 2.1 y 2.2+ es muy apreciada.
Solución 2
Resolví mi propio problema: no puedes regresar null
desde el onBind
Método de su servicio: debe devolver el IBinder
de una AbstractThreadedSyncAdapter
.
Esto tiene el efecto no deseado de agregar una entrada a la sección de datos y sincronización de la página de configuración de la cuenta, a pesar de que mi implementación de AbstractThreadedSyncAdapter
no hace nada; Esperaba evitar esto.
Para resumir, para utilizar el sistema de cuentas en Android debe:
- Implementar un servicio que tenga un
IntentFilter
porandroid.content.SyncAdapter
. - Este servicio debe devolver el
IBinder
de unaAbstractThreadedSyncAdapter
Implementación de IT esonBind
método. - Esto luego requiere que tengas un
ContentProvider
(puede ser solo una implementación de stub) que se conoce como elcontentAuthority
En su archivo XML SyncAdapter. - Esto tiene la desventaja de que su ContentProvider se enumera en el encabezado de datos y sincronización en la página de configuración de su cuenta.
Otros consejos
Dado que esta es la única pregunta que he visto relacionada con este problema, aquí hay una respuesta de año tardío. También me encontré con el problema permanente de bloqueo de wake debido al sistema de Android que sincroniza mi cuenta personalizada automáticamente.
La mejor manera de manejar esto, que requiere un código mínimo y en realidad lo hace para que la cuenta nunca se sincronice a menos que se llame específicamente para sincronizar en el código:
ContentResolver.setIsSyncable(account, ContactsContract.AUTHORITY, 0);
Ahora esto requiere que en el momento en que cree su cuenta llame a este método estático. Mientras que el primer parámetro es la cuenta para establecer esta configuración, el segundo parámetro es la autoridad de ContentProvider usado, y el tercero es el entero que cuando se establece en un número positivo permite sincronizar, cuando se establece en 0 deshabilitados y cuando se establece en cualquier otra cosa lo hace desconocido. La autoridad para usar se puede encontrar dentro de su "sync_something.xml" bajo el atributo ContentAuthority, que utiliza su 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-->
El archivo XML anterior se especifica dentro de la parte del servicio de su 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>
Este es el fragmento de código que uso para crear mi cuenta personalizada dentro de mi 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);
}
}
La gran parte de esto es que cuando el sistema intenta sincronizar el servicio, verifica si el servicio es sincronizado primero, si se establece en falso, cancela la sincronización. Ahora no tienes que crear el tuyo ContentProvider
Tampoco tu ContentProvider
Se muestre bajo datos y sincronización. Sin embargo, debe tener una implementación de Stub de AbstractThreadedSyncAdapter que devuelve un Ibinder dentro de su método de Onbind. Y por último, pero no menos importante, hace que un usuario no pueda habilitar la sincronización o usar el botón "Sync Now" para esta cuenta a menos que haya agregado la funcionalidad dentro de su aplicación.