sirve - sync data android
¿Por qué ContentResolver.requestSync no desencadena una sincronización? (1)
Llamar requestSync()
solo funcionará en un par de {Account, ContentAuthority} conocido por el sistema. Su aplicación debe realizar una serie de pasos para decirle a Android que puede sincronizar un tipo específico de contenido con un tipo de cuenta específico. Lo hace en el AndroidManifest.
1. Notifique a Android que su paquete de aplicaciones brinda sincronización
En primer lugar, en AndroidManifest.xml, debe declarar que tiene un Servicio de sincronización:
<service android:name=".sync.mySyncService" android:exported="true">
<intent-filter>
<action android:name="android.content.SyncAdapter" />
</intent-filter>
<meta-data
android:name="android.content.SyncAdapter"
android:resource="@xml/sync_myapp" />
</service>
El atributo name de la etiqueta <service>
es el nombre de tu clase para conectar la sincronización ... Hablaré de eso en un segundo.
Al establecer el valor exportado verdadero, es visible para otros componentes (necesario para que ContentResolver
pueda ContentResolver
).
El filtro de intención le permite detectar un intento de solicitar sincronización. (Esta Intent
proviene de ContentResolver
cuando llamas a ContentResolver.requestSync()
o a métodos de programación relacionados).
La etiqueta <meta-data>
tratará a continuación.
2. Proporcione a Android un servicio utilizado para encontrar su SyncAdapter
Entonces la clase en sí ... Aquí hay un ejemplo:
public class mySyncService extends Service {
private static mySyncAdapter mSyncAdapter = null;
public SyncService() {
super();
}
@Override
public void onCreate() {
super.onCreate();
if (mSyncAdapter == null) {
mSyncAdapter = new mySyncAdapter(getApplicationContext(), true);
}
}
@Override
public IBinder onBind(Intent arg0) {
return mSyncAdapter.getSyncAdapterBinder();
}
}
Su clase debe extender Service
o una de sus subclases, debe implementar public IBinder onBind(Intent)
, y debe devolver un SyncAdapterBinder
cuando se lo llame ... Necesita una variable de tipo AbstractThreadedSyncAdapter
. 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 su clase en cuanto a lo que es su SyncAdapter
.
3. Proporcione un class SyncAdapter
para realmente realizar la sincronización.
mySyncAdapter es donde se almacena la lógica de sincronización real. Su método onPerformSync()
se llama cuando es hora de sincronizar. Me imagino que ya tienes esto en su lugar.
4. Establezca un enlace entre un tipo de cuenta y una autoridad de contenido
Mirando hacia atrás en AndroidManifest, esa extraña etiqueta <meta-data>
en nuestro servicio es la pieza clave que establece el enlace entre una Autorización de Contenido y una cuenta. Hace referencia externamente a otro archivo xml (llámalo como quieras, algo relevante para tu aplicación). Veamos sync_myapp.xml:
<?xml version="1.0" encoding="utf-8" ?>
<sync-adapter
xmlns:android="http://schemas.android.com/apk/res/android"
android:contentAuthority="com.android.contacts"
android:accountType="com.google"
android:userVisible="true" />
De acuerdo, entonces, ¿qué hace esto? Le dice a Android que el adaptador de sincronización que hemos definido (la clase que fue llamada en el elemento de nombre de la etiqueta <service>
que incluye la etiqueta <meta-data>
que hace referencia a este archivo ...) sincronizará contactos usando un cuenta de estilo com.google.
Todo su contenido Las cadenas de autoridad tienen que coincidir y coincidir con lo que está sincronizando: esta debe ser una cadena que defina, si está creando su propia base de datos, o debería usar algunas cadenas de dispositivos existentes si está sincronizando las conocidas. tipos de datos (como contactos o eventos de calendario o lo que sea). Lo anterior ("com.android.contacts") pasa a ser la cadena ContentAuthority para los datos de tipo contactos (sorpresa, sorpresa).
accountType también tiene que coincidir con uno de esos tipos de cuenta conocidos que ya se han ingresado, o tiene que coincidir con uno que está creando (Esto implica crear una subclase de AccountAuthenticator para obtener autenticación en su servidor ... Vale la pena un artículo, en sí mismo). De nuevo, "com.google" es la cadena definida que identifica las credenciales de la cuenta de estilo de google.com (nuevamente, esto no debería ser una sorpresa).
5. Habilite la sincronización en un par de cuentas / ContentAuthority determinado
Finalmente, la sincronización debe estar habilitada. Puede hacerlo 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:
ContentResolver.setSyncAutomatically(account, AUTHORITY, true);
Para que se produzca la sincronización, su par de cuenta / autoridad debe estar habilitado para sincronizarse (como en el ejemplo anterior) y el indicador global de sincronización global en el sistema debe estar configurado y el dispositivo debe tener conectividad de red.
Si la sincronización de su cuenta / autoridad o la sincronización global están deshabilitadas, la llamada a RequestSync () tiene un efecto: establece un indicador de que se ha solicitado la sincronización, y se realizará tan pronto como se habilite la sincronización.
Además, por mgv , configura ContentResolver.SYNC_EXTRAS_MANUAL
en true en el paquete de extras de su requestSync le pedirá a android que fuerce la sincronización incluso si la sincronización global está desactivada (respete a 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 de @ gmail.com configuradas en un dispositivo o dos cuentas de Facebook, o dos cuentas de Twitter, etc.). Debería considerar las implicaciones de la aplicación al hacer eso. .. Si tiene dos cuentas, probablemente no desee intentar sincronizarlas en las mismas tablas de la base de datos. Tal vez deba especificar que solo uno puede estar activo a la vez, vaciar las tablas y volver a sincronizar si cambia de cuenta. (a través de una página de propiedades que consulta qué cuentas están presentes). Tal vez crees una base de datos diferente para cada cuenta, tal vez diferentes tablas, tal vez una columna clave en cada tabla. Todas las aplicaciones específicas y dignas de pensar. ContentResolver.setIsSyncable(Account account, String authority, int syncable)
puede ser de interés aquí. setSyncAutomatically()
controla si un par de cuenta / autoridad está marcado o desmarcado , mientras que setIsSyncable()
proporciona una forma de desmarcar y poner gris la línea para que el usuario no pueda activarla. Puede establecer una cuenta Syncable y la otra no Syncable (dsabled).
7. Tenga en cuenta ContentResolver.notifyChange ()
Una cosa difícil. ContentResolver.notifyChange()
es una función utilizada por ContentProvider
s para notificar a Android que se ha cambiado la base de datos local. Esto sirve para dos funciones, primero, hará que los cursores sigan ese contenido uri para actualizar, y a su vez vuelva a consultar, invalidar y volver a dibujar un ListView
, etc. Es muy mágico, la base de datos cambia y tu ListView
simplemente se actualiza automáticamente. Increíble. Además, cuando la base de datos cambie, Android solicitará Sync 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 increíble.
Sin embargo, hay un caso de borde. Si extraes del servidor e insertas una actualización en ContentProvider
, se llamará notifyChange()
y android notifyChange()
"¡Oh, cambios en la base de datos, mejor notifyChange()
en el servidor!" (Doh!) ContentProviders
bien escritos tendrá algunas pruebas para ver si los cambios vinieron de la red o del usuario, y establecerá el syncToNetwork
booleano syncToNetwork
falso, si es así, para evitar esta derrochadora sincronización. Si está cargando datos en ContentProvider
, le corresponde averiguar cómo hacerlo funcionar. De lo contrario, terminará realizando siempre 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 esté habilitada, Android sabrá cómo conectar todo para usted, y la sincronización debería comenzar a funcionar. En este punto, muchas cosas agradables simplemente se ajustarán y se parecerá mucho a la magia. ¡Disfrutar!
Estoy tratando de implementar el patrón de Adaptador de Proveedor de Contenido-Proveedor como se discutió en Google IO - diapositiva 26. Mi proveedor de contenido está funcionando y mi sincronización funciona cuando la disparo desde la aplicación Dev Tools Sync Tester, sin embargo, cuando llamo a ContentResolver. requestSync (cuenta, autoridad, paquete) de ContentProvider, mi sincronización nunca se activa.
ContentResolver.requestSync(
account,
AUTHORITY,
new Bundle());
Editar - fragmento de manifiesto agregado Mi manifiesto xml 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 que se pasa a requestSync es de "myaccounttype" y la AUTORIDAD que se transfiere a la llamada coincide con mi adaptador syc xml.
¿ContentResolver.requestSync es la forma correcta de solicitar una sincronización? Parece que la herramienta del comprobador de sincronización se une directamente al servicio y las llamadas inician la sincronización, pero parece que eso frustra 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é el probador de sincronización funcionaría, pero no mi llamada a ContentResolver.requestSync? ¿Hay algo que deba pasar en el paquete?
Estoy probando en el emulador en dispositivos con 2.1 y 2.2.