Estoy tratando de implementar el patrón Content-Provider-Sync Adapter como se discutió en Google IO - diapositiva 26. Mi proveedor de contenido está funcionando y mi sincronización funciona cuando lo activo desde la aplicación Dev Tools Sync Tester, sin embargo, cuando llamo a ContentResolver. requestSync (cuenta, autoridad, paquete) de mi ContentProvider, mi sincronización nunca se activa.
ContentResolver.requestSync(
account,
AUTHORITY,
new Bundle());
Editar: fragmento de manifiesto agregado Mi archivo XML de manifiesto contiene:
<service
android:name=".sync.SyncService"
android:exported="true">
<intent-filter>
<action
android:name="android.content.SyncAdapter" />
</intent-filter>
<meta-data android:name="android.content.SyncAdapter"
android:resource="@xml/syncadapter" />
</service>
--Editar
Mi syncadapter.xml asociado con mi servicio de sincronización contiene:
<?xml version="1.0" encoding="utf-8"?>
<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
android:contentAuthority="AUTHORITY"
android:accountType="myaccounttype"
android:supportsUploading="true"
/>
No estoy seguro de qué otro código sería útil. La cuenta pasada a requestSync es de "myaccounttype" y la AUTORIDAD pasada a la llamada coincide con mi adaptador syc xml.
¿ContentResolver.requestSync es la forma correcta de solicitar una sincronización? Parece que la herramienta de prueba de sincronización se vincula directamente con el servicio y las llamadas comienzan a sincronizarse, pero parece que anula el propósito de la integración con la arquitectura de sincronización.
Si esa es la forma correcta de solicitar una sincronización, ¿por qué funcionaría el probador de sincronización, pero no mi llamada a ContentResolver.requestSync? ¿Hay algo que deba pasar en el paquete?
Estoy probando en el emulador en dispositivos que ejecutan 2.1 y 2.2.
android:process=":sync"
del servicio de sincronización permitió que el depurador golpeara los puntos pico. El servicio de sincronización en sí estaba funcionando antes de eso, porque podía ver los mensajes de registro delonPerformSync
método en nombre de otro proceso.Respuestas:
Las llamadas
requestSync()
solo funcionarán en un par {Account, ContentAuthority} que sea conocido por el sistema. Tu aplicación debe seguir una serie de pasos para indicarle a Android que eres capaz de sincronizar un tipo específico de contenido usando un tipo específico de cuenta. Hace esto en el AndroidManifest.1. Notifique a Android que el paquete de su aplicación proporciona sincronización
En primer lugar, en AndroidManifest.xml, debe declarar que tiene un Servicio de sincronización:
El atributo de nombre de la
<service>
etiqueta es el nombre de su clase para conectar la sincronización ... Hablaré de eso en un segundo.Establecer exported true lo hace visible para otros componentes (necesario para
ContentResolver
poder llamarlo).El filtro de intención le permite detectar una intención que solicita sincronización. (Esto
Intent
proviene deContentResolver
cuando llamaContentResolver.requestSync()
o de métodos de programación relacionados).La
<meta-data>
etiqueta se discutirá a continuación.2. Proporcione a Android un servicio utilizado para encontrar su SyncAdapter
Entonces, la clase en sí ... Aquí hay un ejemplo:
Su clase debe extender
Service
o una de sus subclases, debe implementarpublic IBinder onBind(Intent)
y debe devolver unSyncAdapterBinder
cuando se llama ... Necesita una variable de tipoAbstractThreadedSyncAdapter
. Como puede ver, eso es prácticamente todo en esa clase. La única razón por la que está ahí es para proporcionar un Servicio, que ofrece una interfaz estándar para Android para consultar a su clase sobre lo que es ustedSyncAdapter
mismo.3. Proporcione una
class SyncAdapter
para realizar la sincronización.mySyncAdapter es donde se almacena la lógica de sincronización real. Se
onPerformSync()
llama a su método cuando llega el momento de sincronizar. Supongo que ya tiene esto en su lugar.4. Establecer un vínculo entre un tipo de cuenta y una autoridad de contenido.
Mirando hacia atrás de nuevo en AndroidManifest, esa extraña
<meta-data>
etiqueta en nuestro servicio es la pieza clave que establece el vínculo entre ContentAuthority y una cuenta. Hace referencia externamente a otro archivo xml (llámelo como quiera, algo relevante para su aplicación). Veamos sync_myapp.xml:Bien, entonces, ¿qué hace esto? Le dice a Android que el adaptador de sincronización que hemos definido (la clase que se llamó en el elemento de nombre de la
<service>
etiqueta que incluye la<meta-data>
etiqueta que hace referencia a este archivo ...) sincronizará los contactos usando una cuenta de estilo com.google.Todas las cadenas de contenido de la autoridad deben coincidir y coincidir con lo que está sincronizando: esta debe ser una cadena que defina, si está creando su propia base de datos, o debe usar algunas cadenas de dispositivos existentes si está sincronizando. tipos de datos (como contactos o eventos de calendario o lo que sea). Lo anterior ("com.android.contacts") resulta ser la cadena ContentAuthority para los datos del tipo de contactos (sorpresa, sorpresa).
accountType también tiene que coincidir con uno de esos tipos de cuenta conocidos que ya están ingresados, o tiene que coincidir con uno que está creando (esto implica crear una subclase de AccountAuthenticator para obtener la autenticación en su servidor ... Vale la pena un artículo en sí). Nuevamente, "com.google" es la cadena definida que identifica ... las credenciales de la cuenta de estilo google.com (nuevamente, esto no debería ser una sorpresa).
5. Habilite la sincronización en un par de cuenta / autoridad de contenido determinado
Finalmente, la sincronización debe estar habilitada. Puede hacer esto en la página Cuentas y sincronización en el panel de control yendo a su aplicación y configurando la casilla de verificación junto a su aplicación dentro de la cuenta correspondiente. Alternativamente, puede hacerlo en algún código de configuración en su aplicación:
Para que se produzca la sincronización, su par de cuenta / autoridad debe estar habilitado para sincronizar (como arriba) y la marca de sincronización global general en el sistema debe estar configurada, y el dispositivo debe tener conectividad de red.
Si la sincronización de su cuenta / autoridad o la sincronización global están deshabilitadas, llamar a RequestSync () tiene un efecto: establece una marca de que se ha solicitado la sincronización y se realizará tan pronto como se habilite la sincronización.
Además, por mgv , si se establece
ContentResolver.SYNC_EXTRAS_MANUAL
en verdadero en el paquete de extras de su solicitud , Sync le pedirá a Android que fuerce una sincronización incluso si la sincronización global está desactivada (¡sea respetuoso con su usuario aquí!)Finalmente, puede configurar una sincronización programada periódica, nuevamente con las funciones de ContentResolver.
6. Considere las implicaciones de múltiples cuentas
Es posible tener más de una cuenta del mismo tipo (dos cuentas @ gmail.com configuradas en un dispositivo o dos cuentas de Facebook, o dos cuentas de Twitter, etc.). Debe considerar las implicaciones de aplicación de hacerlo. .. Si tiene dos cuentas, probablemente no quiera intentar sincronizar ambas en las mismas tablas de la base de datos. Tal vez necesite especificar que solo uno puede estar activo a la vez, y vaciar las tablas y resincronizar si cambia de cuenta. (a través de una página de propiedades que consulta qué cuentas están presentes). Tal vez cree una base de datos diferente para cada cuenta, tal vez tablas diferentes, tal vez una columna clave en cada tabla. Toda aplicación específica y digna de reflexión.
ContentResolver.setIsSyncable(Account account, String authority, int syncable)
podría ser de interés aquí.setSyncAutomatically()
controla si un par de cuenta / autoridad está verificado odesmarcado , mientras quesetIsSyncable()
proporciona una forma de desmarcar y atenuar la línea para que el usuario no pueda activarla. Puede configurar una cuenta Syncable y la otra no Syncable (dsabled).7. Tenga en cuenta ContentResolver.notifyChange ()
Una cosa complicada.
ContentResolver.notifyChange()
es una función utilizada porContentProvider
s para notificar a Android que se ha cambiado la base de datos local. Esto tiene dos funciones, primero, hará que los cursores que siguen ese contenido uri se actualicen y, a su vez, vuelvan a consultar, invaliden y vuelvan a dibujarListView
, etc. Es muy mágico, la base de datos cambia y tuListView
solo se actualiza automáticamente. Increíble. Además, cuando la base de datos cambie, Android solicitará la sincronización por usted, incluso fuera de su horario normal, para que esos cambios se eliminen del dispositivo y se sincronicen con el servidor lo más rápido posible. También impresionante.Sin embargo, hay un caso de borde. Si extrae del servidor e inserta una actualización en el
ContentProvider
, automáticamente llamaránotifyChange()
y Android dirá: "¡Oh, cambios en la base de datos, mejor colóquelos en el servidor!" (¡Doh!) Bien escritoContentProviders
tendrá algunas pruebas para ver si los cambios provienen de la red o del usuario, y establecerá lasyncToNetwork
bandera booleana como falsa si es así, para evitar esta doble sincronización innecesaria. Si está introduciendo datos en unContentProvider
, le conviene averiguar cómo hacer que esto funcione; de lo contrario, siempre terminará realizando dos sincronizaciones cuando solo se necesita una.8. ¡Siéntete feliz!
Una vez que tenga todos estos metadatos XML en su lugar y la sincronización habilitada, Android sabrá cómo conectar todo por usted, y la sincronización debería comenzar a funcionar. En este punto, muchas cosas que son agradables simplemente encajarán en su lugar y se sentirán como magia. ¡Disfrutar!
fuente
ContentResolver.SYNC_EXTRAS_MANUAL
conjunto a fiel al paquete de extras y forzará la sincronización :)Estaba llamando
setIsSyncable
después delsetAuthToken
método AccountManager . Pero se alcanzó lasetAuthToken
función devuelta antessetIsSyncable
. Después de los cambios de orden, ¡todo funcionó bien!fuente