Unofficial Content

Objetivo

Existen varios escenarios en los que se necesita almacenamiento offline (de aquí en adelante lo llamaremos caching) en una aplicación generada para smart devices.
Detallaremos a continuación aquellos que resolvemos con esta primera implementación de caching en los generadores para Smart Devices.
Aclaremos que esto es practicamente transparente para el desarrollador, el caching lo implementa GeneXus automáticamente.

Escenario 1: Cache de consultas

Lo que se quiere lograr es no tener tráfico de datos entre el cliente y el servidor si los datos en el server no han cambiado.
Este es el caso más básico que deseamos resolver, que es, en una aplicación "100% conectada", evitar consultas repetidas al servidor.

Es deseable evitar el tráfico de red innecesario, principalmente para lograr ahorros en:
-    el uso de ancho de banda (especialmente al usar redes telefónicas en vez de Wi-fi)
-    el uso de energía del dispositivo (comunicación inalámbrica, deserialización de los datos)
-    la carga sobre el servidor web.

Para resolver esto es necesario saber, para una consulta realizada desde el SD, si los datos involucrados en ésta fueron cambiados desde la última vez que fue realizada.

Escenario 2: Aplicación off-line (readonly)

Es una extensión del caso anterior, suponiendo que no hay conectividad. La idea básica es que, teniendo un cache como el explicado, donde si no cambian los datos consultados no será necesario ir al server por estar cacheados, en caso de ausencia de conectividad también podremos recorrer las partes de la aplicación ya visitadas, utilizando los datos almacenados en el dispositivo.

Implementación

Para resolver los dos escenarios anteriores necesitamos dos cosas:

-    Almacenamiento en una base de datos local.
     Los datos que el servidor retorne deben ser guardados en una base de datos, para evitar el consumo exagerado de memoria y sobrevivir al cierre de la aplicación.
     Puesto que lo que interesa almacenar es el resultado de las consultas al servidor, el modelo de datos de esta base correspondería a "una tabla por Data Provider" y no
     al modelo de datos normalizado de GeneXus.

-    Un mecanismo para determinar si los datos han cambiado en el servidor.
     Cada consulta realizada a un Data Provider debe incluir la fecha de última actualización de los datos que retorna. El cliente almacena esta fecha en su cache, junto con
     los datos, y la reenvía en cada consulta posterior.
     Si el servidor determina que dicha fecha no ha cambiado (es decir, no ha habido actualizaciones posteriores) entonces retorna una respuesta especial (HTTP 304)
     para indicarlo. El cliente interpreta esta respuesta y despliega los mismos datos que ya tenía.
     Este mecanismo es el mismo que usan los browsers al comunicarse con servidores web. También desplegara los datos cacheados si no tiene conectividad con el server.

La Base de Datos que utilizamos es SQLite, la cual ya viene con todos los dispositivos.

Implementación en el Server

Cuando el cliente realiza una consulta, junto con ésta envía el timestamp de la última respuesta (o sea, el momento en que realizo la consulta la última vez) , el server debe controlar si alguna de las tablas involucradas en la consulta cambiaron desde ese momento para determinar qué devolver: si la última consulta realizada por el cliente es anterior a la actualización de sus datos (o sea, si las tablas relacionadas con la consulta fueron modificadas), el server devuelve el nuevo resultado, sino devuelve un mensaje que indica que los datos que el cliente posee siguen vigentes, ante lo cual el cliente muestra el resultado que tiene cacheado.

Dada una consulta de este tipo, para poder determinar en el server si los datos del cliente están vigentes, se necesitan dos cosas:

1) La lista de tablas involucradas en la consulta

2) Un registro con el momento en que estas tablas fueron modificadas la última vez

Teniendo las tablas involucradas, basta con comparar el timestamp que provee el cliente con cada una de los registros correspondientes a las tablas involucradas para ver si alguno de ellos es posterior, en cuyo caso hay que reenviar el resultado.

Para implementar esto, todas las aplicaciones generadas con GeneXus mantienen un registro global del timestamp de actualización de cada tabla. En este registro se inserta/actualiza una entrada cuando se actualiza una tabla de la DB.

Por lo tanto, el cache de las aplicaciones para SD, siempre tendrán la información necesaria para saber si puede usar el cache o debe realizar nuevamente la consulta.

La única excepción es si alguna tabla de la DB del sistema es actualizada por fuera de las aplicaciones desarrolladas con GeneXus.

Es entre otras cosas, para solucionar esta situación, que se habilitan las siguientes propiedades a nivel de los objetos para Smart Devices en la sección Caching.
 

CachingCategoryProperties

Enable Data Caching

Esta propiedad tiene dos valores, True o False.

En caso de estar en false, se deshabilita el Caching para ese objeto para smart device. Esto quiere decir, que siempre que se haga una consulta a dicho objeto, independientemente si alguna de las tablas involucradas en la consulta fue actualizada o no, se realiza la consulta a la base de datos. Con esto solucionamos el caso explicado anteriormente si una tabla es modificada por fuera de GeneXus. Como contrapartida, dicho objeto para smart device no devolverá datos si se esta ejecutando sin conexión, ni optimizara el uso de los recursos del dispositivo.

Si la propiedad anterior esta en True (valor por default), se habilita una nueva propiedad:

Check for new data

Esta nueva propiedad tiene dos valores, Every time o After elapsed time.

Con el valor every time, se habilita para ese objeto el caching como se explicó anteriormente, o sea, si la consulta esta cacheada, se consultan los datos del cache chequeando con el servidor si los datos cambiaron, en cuyo caso realiza nuevamente la consulta.

Seleccionando After elapsed time, se habilita una vez más una nueva property:

Check For New Data After Minutes Elapsed

En ella se puede indicar en minutos, el tiempo de espera para chequear con el servidor si los datos cacheados cambiaron.

Supongamos elegimos 5 minutos (que es el valor por defecto), si tenemos los datos cacheados para una consulta, por más que los datos hayan cambiado en el servidor, no se chequeara esto hasta transcurridos 5 minutos desde la última vez que se realizó esta misma consulta, durante este periodo se mostraran los datos cacheados. Una vez transcurrido este tiempo se procede con el mecanismo normal, o sea, se muestra lo cacheado pero se pregunta al server si dichos datos cambiaron, en cuyo caso se realiza nuevamente la consulta al server.

El objetivo principal de esta property es para ser usado en consultas, las cuales, sabemos tienen pocas actualizaciones a lo largo del tiempo (un ejemplo seria sobre la tabla de Países).

 

Smart Device Cache Management Property

Existe a nivel de generador, cuando este es for Smart Devices, una property llamada Smart Device Cache Management, la cual tiene dos valores, On y Off.

Todo lo dicho anteriormente vale si dicha property tiene el valor On, que es su valor por default. Si se selecciona el valor Off lo que sucede es que, si bien las consultas serán cacheadas igual, permitiendo trabajar off line, si se está trabajando on line, no se optimizan las consultas, siempre se accederá a la DB independientemente si los datos cambiaron o no.

Escenario 3

Existen escenarios en los que específicamente necesitamos inhabilitar el cache (por ejemplo a efectos de forzar que la aplicación refresque el form del device o porque los datos son modificados desde una aplicación no GeneXus, entre otros casos).

Supongamos el siguiente caso a modo de ejemplificar el escenario.

Se tiene un Panel for Smart Devices en cuyo form se muestra una variable y atributos de la base de datos.
En una Action del panel se llama a un procedimiento y al retornar se realiza un refresh, en dicho refresh se carga la variable que está en el form con el contenido de la websession la cual fue modificada en el procedimiento.

Los eventos del Panel for Smart Devices serían como sigue:

Event ‘CallProc’
   Composite
      ModifyWebSession.Call()
      refresh
   EndComposite
EndEvent

Event Refresh
   &FormVar =&websession.get(‘Sample’)
Endevent

Si el procedimiento ModifyWebSession simplemente hace lo siguiente:

&websession.set(‘Sample’, &time)

Al retornar al Panel for Smart Devices, la variable &FormVar en el panel, nunca se verá modificada (a menos que los atributos presentes en el form realmente hayan sido modificados), ya que el panel, al ejecutar la consulta a la base de datos, recibirá como respuesta que los datos no fueron modificados, por lo tanto el refresh no se ejecutara y como consecuencia no se verán cambios en la variable &FormVar.

Para resolver esta situación se implementó una forma de invalidar el cache programáticamente, de tal forma que independientemente si los datos cambiaron o no realmente, se considere que la consulta a la base de datos se debe hacer igual (como si los datos hubieran cambiado).

Esto se implementó como un external object, el cual se importa cuando se utiliza el Smart Device generator (al igual que todos los external objects que se consolidan automáticamente dentro de la carpeta SmartDevicesApi).  Esta clase se llama ServerAPI y contiene el método InvalidateCache.

Por lo tanto, en el ejemplo anterior, el procedimiento ModifyWebSession, debería hacer uso de esta a efectos que el cache quede invalido y al retornar al Panel for Smart Device, este considere que los datos cambiaron y efectúe la consulta nuevamente (con el correspondiente refresh). El procedimiento quedaría de la siguiente forma:

&websession.set(‘Sample’, &time)
ServerAPI.InvalidateCache()

Ver también

Enable Data Caching Property

Check For New Data Property

Smart Devices Cache Management property

Nota: por el momento esta solamente implementado para Android e iOS

Last update: February 2024 | © GeneXus. All rights reserved. GeneXus Powered by Globant