Skip to content

Correr el SyncAdapter

Andrés Matte edited this page Feb 25, 2016 · 3 revisions

Debes tratar de correr el SyncAdapter basado en un calendario o como resultado indirecto de algún evento. Por ejemplo, puedes realizar la sincronización en un momento particular del día, o cuando hayan cambios en los datos almacenados en el dispositivo. Debes evitar correr la sincronización por una acción directa del usuario porque haciendo esto no aprovechas todos los beneficios de una sincronización calendarizada.

Para realizar la sincronización tienes varias alternativas basadas en distintos eventos.

Datos del servidor cambian

Cambiar los datos en respuesta a un mensaje desde el servidor indicando que los datos han cambiado. Esta opción te permite actualizar los datos sin utilizar mucha batería y mejora bastante el desempeño. No cubriremos en detalle ya que requiere utilizar Google Cloud Messaging (GCM), tema que da para un tutorial por si solo.

Datos del content provider cambian

Para realizar esto debes registrar un observer para el content provider. Cuando los datos en el content provider cambia, el content provider framework llama al observer. En el observer se debe llamar a requestSync() para decirle al framework que corra el sync adapter. También es muy importante que cuando se quiera hacer la sincronización se debe llamar a ContentResolver.notifyChange(uri, null). Esto le avisa a los observadores que se ha hecho un cambio y ellos toman las acciones especificadas. En este caso se usa en el método ContentProvider.insert().

Para crear el observer debes extender la clase ContentObserver e implementar el método onChange(). Dentro de este método debes llamar a requestSync() para iniciar el SyncAdapter. Para registrar al observer hay que pasar esta clase como argumento de registerContentObserver(). También debes pasar un content URI que indica los datos que quieres observar. La clase observer quedaría como sigue:

        public class TableObserver extends ContentObserver {
            /**
             * Crea un content observer
             *
             */
            public TableObserver(Handler handler) {
                super(handler);
            }

            /*
             * Define el metodo que es llamado cuando los datos en el content provider cambian.
             * Este metodo es solo para que haya compatibilidad con plataformas mas viejas.
            */
            @Override
            public void onChange(boolean selfChange) {
                onChange(selfChange, null);
            }
            /*
             * Define el metodo que es llamado cuando los datos en el content provider cambian.
             */
            @Override
            public void onChange(boolean selfChange, Uri changeUri) {

                if (mAccount != null) {
                    // Corre la sincronizacion
                    ContentResolver.requestSync(mAccount, StudentsContract.AUTHORITY, null);
                }
            }
        }

Luego para registrar el observer tenemos que hacer lo siguiente:

    // En activity.onCreate()
    ...
    TableObserver observer = new TableObserver(null);
    /*
     * Registra el obsever para students
     */
    mResolver.registerContentObserver(StudentsContract.STUDENTS_URI, true, observer);
    ...

Hay un Network Message

La documentación de Google sugiere que se puede correr el SyncAdapter cada vez que haya un Network Message. Esto significa que la sincornización se realizará regularmente cuando haya conexión a internet. Por lo probado esto no funciona como la documentación indica. Lo único que asegura este método es que el SyncAdapter se corra en algún momento en un lapso de 24 horas.

Configurar esta forma de sincronizar es bastante sencillo, solo se debe llamar al método ContentResolver.setSyncAutomatically().

    // En activity.onCreate()
    ...
    mResolver.setSyncAutomatically(mAccount, StudentsContract.AUTHORITY , true);
    ...

Correr SyncAdapter periódicamente

Puedes configurar que el sync adapter se ejecute cada ciertos intervalos de tiempo, o a una hora específica, o ambos. Por ejemplo, puedes subir datos en una hora específica, cuando sabes que tu servidor está menos ocupado. Si ocupas esta estrategia debes procurar que cada dispositivo ejecute la sincronización a una hora ligeramente diferente, para no sobrecargar el servidor.

Una sincronización periódica tiene sentido si el usuario no necesita actualización instantanea pero si necesita que los datos se actualicen regularmente. Un ejemplo podría ser una aplicación de noticias. Sería bueno que la ejecución se realice cuando se han publicado las noticias de la mañana, por lo que una sincronización un poco después de eso podría ser de utilidad.

Para utilizar esta opción debes usar el método addPeriodicSync(). Esto hace que se ejecute la sincronización luego de que un tiempo determinado a pasado. Este tiempo puede variar en algunos segundos para que el framework pueda optimizar las veces que se utiliza el internet al coordinarlo con otros sync adpaters.

Para correr el sync adapter a ciertas horas específicas diariamente debes usar AlarmManager, tema que no se revisará en este tutorial. El método addPeriodicSync() y el setSyncAutomatically() pueden ir juntos perfectamente.

Correr SyncAdapter por acción del usuario

Es una opción muy poco recomendada, debido a que hace un uso ineficiente de la calenderización del framework. Si se quiere utilizar, se debe usar el método requestSync() frente a la acción específica del usuario. Es importante acá entregar como parámetros unos flags que indiquen que se quiere realizar una sincronización manual. Con estos se le dice al framework que olvide su filosofía y haga la sincronización de inmediato. Se debe usar de la siguiente manera:

      Bundle settings = new Bundle();
      // Fuerza sincronizacion manual
      settings.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
      // Que se realice de inmediato. Si no se pone este se puede esperar varios segundos hasta que el framework decida ejecutar la sincronizacion.
      settings.putBooleanContentResolver.SYNC_EXTRAS_EXPEDITED, true);
      ContentResolver.requestSync(mAccount, AUTHORITY, settingsBundle);

Siguiente: Comentarios.