Actualizando una base de datos local desde un servidor remoto - Parte III (final)

En la parte final de este artículo, vamos a crear un mecanismo que permita descargar la base de datos alojada en el servidor remoto y alojarla en una ruta local en nuestro smartphone.

Para ello vamos a utilizar el Framework de desarrollo Titanium Mobile. La ventaja es que prácticamente el mismo código nos va a servir para desplegarlo en plataforma Apple o en plataforma Android con un mínimo o casi ningún cambio.

Estructura de la aplicación

La aplicación en Titanium Mobile está compuesta principalmente por dos archivos:
  • app.js que es la aplicación de pruebas del mecanismo de actualización
  • updatedb.js que es una biblioteca o librería que contiene el mecanismo de actualización
Para ambas se necesita declarar el espacio de nombres (namespace) común myapp:

myapp = {}

Otro aspecto importante es la naturaleza asincrónica de la actualización. La librería comienza la actualización que en dependencia de la conexión a Internet que tengamos, el tamaño de la base datos y la potencia de nuestro smartphone demorará segundos más o menos y nos notificará cuando este proceso termine.

La librería updatedb.js

La librería updatedb.js está compuesta por:
  • Una estructura de datos de configuración que especifica datos como la url del servidor Web donde se va a alojar la base de datos, el nombre de la base de datos, el nombre del archivo de configuración, etc.
  • Una función updatedb que permite la actualización de la base de datos local a partir de la base de datos remota y un conjunto de funciones auxiliares (helper functions)

Datos de configuración de la librería

Dato
Descripción
url
URL del servidor Web donde hemos alojado la base de datos
db
Nombre de la base de datos
cf
Nombre del archivo de configuración que contiene una fecha en formato YYYYMMDD (ejemplo 20130226)
timeout
Tiempo de respuesta para el servidor Web que hemos fijado en unos 10,000 milisegundos o 10 segundos por defecto
android
True indica que vamos a ejecutar la aplicación en un smartphone Android, False indica que vamos a ejecutarla en un smartphone de Apple
debug
En True indica si queremos visualizar mensajes que nos ayuden a la puesta a punto. Una vez lista para desplegar en Producción este campo debería ser False
debugcb
Debug Callback. Llama a esta función cuando se produce una situación de depuración
updatecb
Update Callback. Llama a esta función cuando termina la actualización de la base de datos
errorcb
Error Callback. Llama a esta función cuando se produce un error catastrófico durante la actualización
winx
Ventana principal de la aplicación
olddate
Fecha de la configuración local o última actualización que registramos
newdate
Fecha de la configuración remota

La función updatedb

Básicamente la función de actualización de la base de datos:

myapp.dbu.actind = 
Titanium.UI.createActivityIndicator({ height:25, width:25 });
    
// If the application is running in iOS
if (!myapp.dbu.android){
// Setting the activity indicator style
myapp.dbu.actind.style = 
    Titanium.UI.iPhone.ActivityIndicatorStyle.BIG;
// Adding the indicator to the main window
    myapp.dbu.winx.add(myapp.dbu.actind);
}


Crea un indicador de actividad para darle al usuario feedback de que está ocurriendo el proceso de actualización.

if (Titanium.Network.networkType !== 
    Titanium.Network.NETWORK_NONE){
// Get the remote config file with the date to update  
     myapp.dbu.getremoteconfig();
 }


Si hay conexión a Internet procesa el archivo de configuración remoto que está alojado en el servidor Web para verificar si hay alguna actualización.

var fcf = Ti.Filesystem.getFile(
    Ti.Filesystem.applicationDataDirectory,myapp.dbu.cf);

// if there is not a configuration file 
// in the application directory     

if (!fcf.exists()){
   // It's the first time we need to update 
   // the database and no network connection 
   var alertDialog = Titanium.UI.createAlertDialog({
       title: 'WARNING!',
       message: 'You need an internet connection'+ 
                'to update your application data!',
       buttonNames: ['OK']
       });
   // Show alert dialog
      alertDialog.show();
  // Close application because 
  // there is not information or data to process
      myapp.dbu.winx.close();
}

Si no hay conexión a Internet busca si hay un archivo de configuración local en nuestro smartphone. Si no existe, es la primera vez que se realiza la actualización por lo que terminamos con un mensaje de error ya que no es posible actualizar nuestra aplicación.

if (myapp.dbu.updatecb != null) {
     myapp.dbu.updatecb();
 }


Si a pesar de que no hay conexión, ya teníamos una actualización previa, llama a la función updatecb() para que la aplicación acceda a la base de datos.

Creando la aplicación demo

Creamos una aplicación en Titanium Mobile y añadimos la librería updatedb.js a la carpeta Android en Recursos. A continuación, borramos el contenido de app.js y añadimos lo siguiente:

// Background color
Titanium.UI.setBackgroundColor('#000');

// Global namespace
var myapp = {};

// Application main windows
var win1 = Titanium.UI.createWindow({
    title:'DemoDB',
    backgroundColor:'#fff',
    exitOnClose: true
});


Lo primero establece el color de fondo de la ventana de aplicación a negro. Luego declaramos el espacio de nombres global y creamos una ventana a la que pondremos el título ‘DemoDB’ con color de fondo blanco y que cuando se cierre termine la ejecución de la aplicación.

Luego escribimos la función que va acceder a nuestros datos una vez que termine la actualización:

// Function to list database content
var showdatabase = function()
{  
   // Open database 
   var db = Ti.Database.open('bestres.sqlite3');
   // Execute a query to get a recordset
   var restaurants = 
   db.execute('select name,area,style from restaurants');
   var s = "";
   // while there are records in the recordset 
   while (restaurants.isValidRow()){
     // Get the fields content     
     s += "NAME= "   + restaurants.fieldByName("name") + 
     ",AREA= "  + restaurants.fieldByName("area") +
     ",STYLE= " + restaurants.fieldByName("style") +  ";";
     // Navigate to the next record     
     restaurants.next();
   }
   // Close the recordset
   restaurants.close();
   // Show the records content 
   alert("DATABASE CONTENT => " + s);
}


La función abre la base de datos local sqlite3 local llamada besares.sqlite3 y ejecuta una consulta que devuelve el nombre, area y estilo de los restaurantes almacenados. Luego realiza un bucle mientras se reciban filas de datos y compone una cadena de caracteres con la información, cierra la conexión y muestra la cadena de caracteres formada en una ventana de alerta (popup window).

En este momento podríamos utilizar el resultado de la consulta para rellenar una lista o un grid de nuestra aplicación con los datos actualizados.

Por último añadimos el siguiente código:

// Including library 
Ti.include('updatedb.js');

// Configuring database access
myapp.dbu.url      = 'http://ayalawilson.com/apps/demodb/';
myapp.dbu.db       = 'bestres.sqlite3';
myapp.dbu.cf       = 'bestrescf';
myapp.dbu.debug    = true;
myapp.dbu.updatecb = showdatabase;
myapp.dbu.winx     = win1;

// Updating database
myapp.dbu.updatedb();

// On resume event show database
Ti.App.addEventListener('resume', function() {
      showdatabase();
});

// Open the application main window
win1.open();


Incluimos la librería updatedb.js y configuramos:
  • La url de la carpeta en el servidor Web donde se encuentra la base de datos
  • El nombre de la base de datos
  • El nombre del archivo de configuración que contiene la fecha de actualización
  • Ponemos a debug en true para ver mensajes de depuración
  • Indicamos que el updatecb (Update Callback) será la función showdatabase() que hemos creado previamente
  • Indicamos que la ventana de la aplicación será win1
A continuación llamamos a la función que actualiza la base de datos e indicamos un par de cosas más:
  • Añadimos al evento ‘resume’ (cuando pase de estar minimizada a tener el foco de ejecución) ejecute la función showdatabase() para mostrarnos los datos
  • Abrimos la ventana principal de la aplicación para comenzar su ejecución

Como actualizar la base de datos remota en el servidor
  • Sustituimos el archivo de la base de datos remota
  • Actualizamos el archivo de configuración con la fecha actual
Como se realiza la actualización local

Los terminales móviles cuando arranca la aplicación van al servidor Web e inspeccionan la fecha del archivo de configuración remoto. Si la fecha remota es mayor que la fecha de configuración local de la última actualización, se actualiza la base de datos local (borra la base de datos local y descarga la base de datos remota) en todos los terminales.


Si no hay conexión a Internet en el momento que arranca la aplicación pueden ocurrir dos cosas:
  • Que exista la base de datos local (descargada en otro momento). En ese caso, la aplicación utiliza los datos locales ya descargados
  • Que no exista la base de datos local (la aplicación nunca se ha iniciado). En esta caso nos presenta un mensaje de error y termina
Terminales probados
  • Apple iPhone 4S
  • Samsung Galaxy SII con Android "Jelly Bean" 4.03
Recomendaciones finales

Este escenario de descarga de la base de datos local desde un servidor remoto funciona muy bien para:
  • Aplicaciones que necesitan operar con bases de datos en modo desconectado (offline), lo que permite que un usuario puede consultar la información deseada viajando por el metro o en el campo o en la carretera o en zonas de difícil o ninguna cobertura
  • Bases de datos relativamente de pequeño tamaño para no consumir mucho ancho de banda con las descargas
  • Bases de datos de solo lectura donde los usuarios solo consumen información, pero no aportan nada (ni comentarios, ni ratings, etc.)
  • Actualizaciones poco frecuentes (los mejores restaurantes de una ciudad no cambian todas las semanas)
  • La base de datos, al ser el núcleo de la información y no estar embebida en una carpeta de recursos de nuestra aplicación, permite que esta pueda actualizarse si tener que actualizar la aplicación completa

El código del proyecto

El proyecto está alojado en Google Code en http://code.google.com/p/local-database-updates-from-remote-http-server/. Sois totalmente libres de modificarlo y adaptarlo a vuestro gusto y necesidades.



6 comentarios:

Jorurlo dijo...

Gracias por la serie de posts, me parecen geniales y muy útiles!!!
Yo voy a iniciar un proyecto personal y buscaba algo así.

¿Es posible actualizar solo una tabla de la base de datos?

Jose Manuel Ayala Wilson dijo...

Gracias por leer. Actualizar solo una tabla tendria un enfoque parecido: nos traemos en un fichero plano, XML o JSON, los datos que queremos actualizar de una tabla especifica

Jorurlo dijo...

Ok. Muchas gracias por la rapidez en responder, lo probaré.

Huixcolotla dijo...

Me genera un error en updateconfig
tambien me marca error en el SQL

S.W.Z dijo...

hola, tengo una duda esas librerías se podrían instalar en eclipse?

Jose Manuel Ayala Wilson dijo...

No hace falta instalar nada en Eclipse. El propio IDE de Titanium esta basado en Eclipse, te acostumbraras de inmediato a utilizarlo.

Publicar un comentario

Entrada antigua Inicio