Creación de aplicaciones para BlackBerry con herramientas de código abierto, parte 2: Cómo construir un lector RSS

De la misma forma en la que un código abierto revolucionó el desarrollo de software en el mercado, la proliferación de fuentes de noticias ha sacudido los monopolios tradicionales de fuentes de noticias. En la actualidad se pueden conseguir noticias de varias fuentes de Internet y desde los accesos a Internet de los principales medios. Viajar de un sitio web a otro para leer noticias es posible pero tedioso. ¿Y qué sucede con las actualizaciones de las noticias acerca de historias de interés? ¿No sería mejor agregar las noticias de interés según su conveniencia? Puede hacerlo con un lector para BlackBerry. Aquí en la parte 2 de esta serie "Cómo crear aplicaciones para BlackBerry con herramientas de código abierto", explore el formato de distribución de datos RSS creando un lector BlackBerry RSS apropiado para llevar las novedades a donde sea que vayan usted y su BlackBerry.

Frank Ableson, Author

Después de que terminara su carrera basquetbolista colegial sin un contrato multianual para jugar para los Lakers de Los Ángeles, Frank Ableson cambió su enfoque hacia el diseño de software informático. Disfruta solucionando problemas complejos, particularmente en las áreas de comunicaciones e interfaces de hardware. Cuando no está trabajando, está pasando el tiempo con su esposa Nikki y sus hijos. Es posible contactar a Frank escribiendo a frank@cfgsolutions.com.



11-02-2013

Antes de comenzar

Esta serie explora la tecnología de códigos abiertos y Java™ para el desarrollo de aplicaciones BlackBerry en el contexto de una aplicación móvil para recolectar datos. La Parte 1 ofrece una introducción al desarrollo BlackBerry con una breve introducción a la plataforma, un recorrido por las herramientas de desarrollo BlackBerry y la construcción de una completa aplicación para recolectar datos.

Este tutorial se centra en el desarrollo de una aplicación BlackBerry utilizando un ejemplo de una aplicación móvil de gestión de contenido. Este ejemplo muestra una lectura básica RSS nivelando las herramientas gratuitas disponibles de desarrollo BlackBerry. La experiencia en desarrollo móvil ayuda pero no es necesaria. Las habilidades de programación Java son necesarias para las aplicaciones BlackBerry pero no son un requerimiento específico para este tutorial. Los RSS feeds son la fuente de contenido de datos utilizados para la aplicación de muestra. Estar familiarizado con RSS ayuda pero no es un requisito si solo desea comprender la arquitectura de gestión de contenido de una aplicación móvil.

Acerca de este tutorial

¿Por qué debería preocuparse en escribir un lector RSS para BlackBerry? Los BlackBerry y todos los teléfonos celulares son una parte integral de la vida actual. Nuestros dispositivos móviles tienen más y más interfaces de usuarios (UI) y crecientes capacidades técnicas en cuanto a velocidad de datos, capacidad de almacenamiento y velocidad de procesador. Sin embargo, si no existiera contenido del cual disfrutar en estos supersitios móviles, los dispositivos serían de uso limitado más allá de su uso como teléfono. Necesitamos contenido en nuestros dispositivos. Recuerde "La pluma más peligrosa que la espada" Las palabras escritas tienen importancia. Y en la actualidad, la palabra escrita es digital — y móvil. El flujo gratuito de información y la libertad de suscribirse a noticias de interés es el fundamento de una sociedad libre y abierta. ¿Cuál otra aplicación de tecnología de código abierto sería mejor que un lector RSS para suscribirse a fuentes de información libres?

Este tutorial utiliza el lenguaje de programación Java para construir un lector de noticias móviles para la plataforma BlackBerry. Existen lectores RSS comerciales para los dispositivos móviles pero no es el objetivo de este tutorial competir con las aplicaciones comerciales. Este tutorial muestra cómo construir una aplicación de código abierto para ayudarlo a construir aplicaciones útiles centradas en el contenido y su distribución. Aprenda acerca de cómo manejar los RSS feeds representando nuevos elementos de una variedad de fuentes. Puede utilizar este mismo paradigma en otras aplicaciones como por ejemplo, la gestión de flota de datos móviles, entrega de datos temporales o hasta implementar un motor móvil de búsqueda.

Aunque es una plataforma popular, BlackBerry aún necesita las aplicaciones de terceros. No existe una mejor forma de conseguir logros que habilitando la comunidad abierta de fuentes. Siga este tutorial ya que sienta las bases para una aplicación de código abierto lectora RSS, la cual puede expandir y reorganizar fácilmente para otros fines útiles.

Este tutorial brinda una breve introducción a RSS, luego se sumerge en los requerimientos de un lector RSS para BlackBerry. Puede descargar el código fuente completo para la aplicación BlackBerry.

Requisitos del sistema

Este tutorial muestra cómo utilizar las herramientas de desarrollo BlackBerry para construir un lector RSS de código abierto para BlackBerry. Necesitará el Entorno de desarrollo Java de BlackBerry (JDE) o su equivalente para construir la aplicación. Este tutorial utiliza V4.0.2 del JDE. Este tutorial incluye algunos enlaces de muestra de RSS feed pero puede sustituirlos por sus propios enlaces o como desee.

Códigos de muestra destacados

En este tutorial, se construirá una aplicación móvil lectora RSS llamada IBMRss para BlackBerry. Cuando siga este proceso trate de pensar más allá de un lector de noticias, el formato RSS puede ser nivelado para muchas otras aplicaciones. Puede descargar el código de fuente completo. Los fragmentos del código de fuente incluyen:

Aplicación IBMRss
La clase de aplicación que contiene en punto de entrada de la aplicación.
IBMRssScreen
Clase que contiene los elementos UI, incluyendo menús y ListField. Brinda funciones interactivas para el usuario.
IBMRssStorage
Clase que engloba el almacenamiento de datos, incluyendo varias rutinas de acceso/ayuda.
setupdata
Método responsable de organizar la relación entre los datos almacenados y la interfaz del usuario. Utilizado durante la fase inicial y una vez que los RSS feeds han sido actualizados.
loadFeed
Método que presenta las entradas de un RSS feed específico cuando se lo selecciona en el UI.
showItem
Método que muestra la descripción de un elemento RSS específico y presenta una opción para ver la historia completa.
RSSDescription
Clase invocada mediante showItem para mostrar un elemento RSS específico.
RssKeyListener
Clase responsable por interactuar con el teclado BlackBerry. Busca las teclas Enter y Esc.
drawListRow
Método responsable de dibujar el texto para ListField, el cual es utilizado para mostrar los datos RSS. Se utiliza un ListField para mostrar una colección de RSS feeds y enumerar los elementos en Rss feed específico.
IBMRssXMLHandler
Clase que amplía la clase de DefaultHandler para manejar los eventos de análisis generados por el motor de análisis SAX XML, utilizado para analizar los RSS feeds.
IBMRssComms
Clase responsable de recuperar todos los RSS feeds cuando lo desee. Amplía la clase java.lang.Thread.
Guid
Clase que contiene algunos asociados finales útiles para la comunicación entre subprocesos y para identificar únicamente el almacenamiento de datos de la aplicación.
Utils
Clase que contiene un solo método de interés: dividir. Esto implementa un simple señalizador para procesar los datos almacenados en nuestra RecordStore (implementada por IBMRssStorage).

Sindicación muy sencilla

Esta sección analiza brevemente la historia de RSS, su construcción y usos potenciales. Un vez que comprenda el formato de los datos, puede construir la aplicación.

Conceptos básicos acerca de RSS

Sindicación muy sencilla (RSS) es una estructura de datos utilizada para transmitir contenido web. El formato de los datos ha evolucionado desde finales de los noventa a medida que diferentes equipos trabajaban en esto. A Dave Winer se le atribuye haber sido instrumental en el liderazgo de los formatos RSS durante años, con contribuciones de equipos de Netscape y otros. (Consulte los Recursos para conocer hitos históricos del formato RSS). Lo que importa es que en la actualidad RSS es un formato de datos bastante estable, útil para publicar noticias o datos estandarizados.

Los datos que se publican a diario — por ejemplo, las actualizaciones de blog, la información acerca de noticias o los datos de catálogo — son ideales para el formato RSS. Los lectores RSS abundan en la mayoría de los buscadores de Internet, lo que brinda soporte integrado para manejar los RSS feeds. Un comportamiento típico de un buscador es crear un marcador que contiene un enlace para cada elemento dentro del RSS feed. Feed es utilizado con frecuencia debido a que los datos RSS generalmente provienen de un servidor web como un archivo estático XML enviado directamente desde el sistema de archivos del servidor web o como una base de datos generada de forma dinámica desde el servidor web.

La próxima sección examina la estructura de los RSS V2.0, que es el nivel actual de especificación.

Estructura de datos

La especificación RSS V2.0 incluye dos entidades requeridas debajo de la etiqueta RSS del nivel superior. Podrían existir múltiples entidades con elementos en un cierto RSS feed, además de un canal. Cómo enumerar 1 show como ejemplo (vea los Recursos para obtener más información).

Listado 1. Muestra de RSS feed tomado de harvard.edu
<?xml version="1.0"?>
<rss version="2.0">
   <channel>
      <title>Liftoff News</title>
      <link>http://liftoff.msfc.nasa.gov/</link>
      <description>Liftoff to Space Exploration.</description>
      <language>en-us</language>
      <pubDate>Tue, 10 Jun 2003 04:00:00 GMT</pubDate>
      <lastBuildDate>Tue, 10 Jun 2003 09:41:01 GMT</lastBuildDate>
      <docs>http://blogs.law.harvard.edu/tech/rss</docs>
      <generator>Weblog Editor 2.0</generator>
      <managingEditor>editor@example.com</managingEditor>
      <webMaster>webmaster@example.com</webMaster>
      <item>
         <title>Star City</title>
         <link>http://liftoff.msfc.nasa.gov/news/2003/news-starcity.asp</link>
         <description>How do Americans get ready to work with Russians
 	  aboard the International Space Station? They take a crash
 	  course in culture, language and protocol at Russia's <a
 	  href="http://howe.iki.rssi.ru/GCTC/gctc_e.htm">Star
	  City</a>.</description>
         <pubDate>Tue, 03 Jun 2003 09:39:21 GMT</pubDate>
         <guid>http://liftoff.msfc.nasa.gov/2003/06/03.html#item573</guid>
      </item>
      <item>
         <description>Sky watchers in Europe, Asia, and parts of Alaska
	  and Canada will experience a <a href="http://science
	  .nasa.gov/headlines/y2003/30may_solareclipse.htm">
	  partial eclipse of the Sun</a> on Saturday, May
	  31st.</description>
         <pubDate>Fri, 30 May 2003 11:06:42 GMT</pubDate>
         <guid>http://liftoff.msfc.nasa.gov/2003/05/30.html#item572</guid>
      </item>
      <item>
         <title>The Engine That Does More</title>
         <link>http://liftoff.msfc.nasa.gov/news/2003/
	  news-VASIMR.asp</link>
         <description>Before man travels to Mars, NASA hopes to design
	  new engines that will let us fly through the Solar System
	  more quickly.  El motor propuesto, VASIMR, lograría eso.</description>
         <pubDate>Tue, 27 May 2003 08:37:32 GMT</pubDate>
         <guid>http://liftoff.msfc.nasa.gov/2003/05/27.html#item571</guid>
      </item>
      <item>
         <title>Astronauts' Dirty Laundry</title>
         <link>http://liftoff.msfc.nasa.gov/news/2003/
	  news-laundry.asp</link>
         <description>Compared to earlier spacecraft, the International
	  Space Station has many luxuries, but laundry facilities are
	  not one of them.  En su lugar, los astronautas tienen otras opciones.</description>
         <pubDate>Tue, 20 May 2003 08:56:02 GMT</pubDate>
         <guid>http://liftoff.msfc.nasa.gov/2003/05/20.html#item570</guid>
      </item>
   </channel>
</rss>

Los campos requeridos de la entidad channel:

  • Title— Generalmente corresponde al nombre de la fuente de los datos
  • Link— Un enlace al sitio web que contiene esto o información relacionada
  • Description— Una breve descripción de los RSS feed

Mientras que el elemento de la entidad no solicita específicamente elementos, un típico subconjunto incluye:

  • Title— Título del elemento
  • Link— URL del elemento, con frecuencia una página web llena de noticias
  • Description— Una sinopsis de la historia completa
  • pubDate— Cuando fue publicada esta información

Los elementos de datos mencionados anteriormente son utilizados por la aplicación de prueba, lector RSS, en este tutorial.

A dónde encontrar los datos

Se pueden encontrar RSS feeds en toda la red. Si se encuentra en un sitio y piensa, "Sería genial suscribirme a estos datos", probablemente no sea el primero que lo piensa. Podría encontrar un enlace hacia sus RSS feeds. Muchos sitios actualmente ofrecen contenido de audio como RSS feeds. Por ejemplo, el sitio de developerWorks y el de eWeek ofrecen muchos RSS feeds acerca de una gran variedad de temas. Handango.com, que es un gran centro de información de software de aplicaciones móviles, ofrece sus catálogos en forma de RSS feeds. En algunos sitios, puede encontrar fácilmente enlaces RSS buscando en la imagen de la Figura 1.

Figura 1. Imagen XML que describe los RSS feeds
XML image depicting RSS feeds

La muestra en este tutorial utiliza RSS feeds desde un puñado de fuentes, incluido:

  • Ziff Davis — DevSource
  • developerWorks de IBM
  • New Yorker
  • Answers in Genesis
  • Handango BlackBerry Best Sellers

Esta lista, una pequeñísima fracción de los RSS feed que se encuentran disponibles en Internet, incluye listas de tutoriales, temas de desarrollo, perspectivas religiosas y un catálogo del producto. Existen otros usos para los datos RSS como se discute a continuación

Otros usos de los RSS

Los datos RSS no necesariamente deben ser noticias o información de catálogo. Puede ser cualquier tipo de dato siempre y cuando se encuentre dentro de los confines de la estructura de datos y el uso previsto de los datos RSS. Por ejemplo, un RSS feed de datos puede ser utilizado para publicar pedidos para un técnico móvil o representar resultados de búsqueda desde un motor de búsqueda. El canal de datos representa la información de alto nivel. Los datos del elemento pueden brindar detalles suficientes como para informar al usuario acerca de cada elemento individual. El campo del enlace asociado puede ser utilizado para aprender más.

Por ejemplo, en el caso de una aplicación móvil para trabajadores, title sería el ID del trabajo, description contiene una sinopsis del tiquet de trabajo y link lleva al técnico de regreso al sistema de pedidos de trabajo para obtener más información según sea necesario. A medida que atraviesa este tutorial, piense acerca de otros tipos de datos que podrían ser representados en el formato RSS.

Es hora de construir el lector BlackBerry RSS. Si desea construir la aplicación de prueba, instale una versión del Entorno de desarrollo Java de BlackBerry si aún no lo ha hecho.


Cómo crear el lector RSS para BlackBerry

La mejor forma de aprender es hacer así que comencemos. Esta sección examina cada uno de los elementos más importantes de la aplicación de prueba, incluyendo los fragmentos de código de fuente más relevantes.

La estructura de la aplicación

A lo largo del tutorial creará una aplicación única, pieza por pieza. Puede descargar el código de fuente completo. La Figura 2 muestra los archivos de origen utilizados en la aplicación de muestra.

Figura 2. Archivo del proyecto en BlackBerry JDE
Project file in BlackBerry JDE

El primer fragmento de código a revisar se encuentra en IBMRssApplication.java. Como en cualquier aplicación Java, una aplicación requiere un punto de entrada, por ejemplo, main en el archivo IBMRssApplication.java.

Listado 2. Método principal del archivo IBMRssApplication.java
//
// IBMRssApplication.java
//
// MSI Services, Inc.
// Frank Ableson
// 973.448.0070
// fableson@msiservices.com
// code free to use for any purpose, commercial or otherwise

package com.msi.ibm.rssreader;

// required imports
import net.rim.device.api.ui.*;

// our application 
class IBMRssApplication extends UiApplication
{
    // applicatione entry point
    public static void main(String[] args)
    {
        // create an instance of our app
        IBMRssApplication theApp = new IBMRssApplication();
        // "run" the app
        theApp.enterEventDispatcher();
    }
    // app constructor
    public IBMRssApplication()
    {
        // create an instance of the main screen of our application
        IBMRssScreen screen = new IBMRssScreen();
        // make the screen visible
        UiApplication.getUiApplication().pushScreen(screen); 
    }
}

El método main crea una nueva instancia de la clase IBMRssApplication, que es una extensión de la clase UiApplication. UiApplication se encuentra en el paquete net.rim.device.api.ui. La clase UiApplication es una clase base para todas las aplicaciones BlackBerry que cuentan con un UI.

El constructor de la clase IBMRssApplication crea una instancia de la clase IBMRssScreen. Esta clase está definida e implementada en IBMRssScreen.java. Una vez creada la instancia de IBMRssScreen, se pasa al método pushScreen(). Esto esencialmente trae la pantalla a la vista en el dispositivo.

Antes de explorar la UI de la aplicación, existen algunos aspectos importantes acerca del código a tener en cuenta. La UI depende en gran medida de las funciones contenidas en otras clases.

Almacenamiento persistente

El almacenamiento y la organización de datos son cruciales para muchas aplicaciones y la aplicación de muestra en este tutorial no es la excepción. La clase IBMRssStorage implementada en IBMRssStorage.java es responsable de gestionar datos para la aplicación de muestra. Los datos se almacenan en un RecordStore, que puede ser encontrado en el paquete javax.microedition.rms. La clase IBMRssStorage posee una cierta cantidad de métodos de ayuda para manipular los registros almacenados y tres clases contenidas que representan construcciones importantes para la aplicación.

Los datos almacenados dentro de una RecordStore como una serie de conjunto de datos de acceso aleatorio y extensión variable. El tutorial de esta aplicación de muestra utilizas una sola RecordStore con dos tipos diferentes de registro: un registro de cabecera que representa un RSS feed y un registro detallado que representa un elemento RSS. Cuando la aplicación procesa los datos RSS, los divide en estos dos tipos de registro y continúa. Este enfoque fue seleccionado ya que en una aplicación personalizada podría haber más elementos de datos agregados (o sustraídos) más allá del formato de datos utilizada en la distribución de los mismos.

El almacenamiento de los datos hace que la aplicación tenga una memoria más eficiente y la brinda acceso más veloz a datos. Para conservar espacio, todos los registros son almacenados como una tubería delimitada de textos. La clase Utils implementada en Utils.java, contiene el método split, que es utilizado en partes del código para facilitar la manipulación de estos registros analizándolos y ubicando los elementos de datos individuales en elementos de una instancia a java.util.Vector.

La estructura de un registro de cabecera es H | Nombre del Feed | URL de la fuente del Feed | Fecha de publicación. El detalle de registro se define como D | Nombre del Feed | Título del elemento | Enlace a la historia completa | Descripción | Fecha de publicación.

Enumere 3 porciones de shows de la clase IBMRssStorage responsable de abrir y cerrar la RecordStore y algunos métodos de ayuda para recuperar registros.

Listado 3. Fragmento de clase IBMRssStorage
class IBMRssStorage 
{
    private RecordStore store;
    IBMRssStorage() 
    {
        try
        {
            store = RecordStore.openRecordStore(Guid.recordStoreName,true);
            store.setMode(RecordStore.AUTHMODE_ANY,true);
        }
        catch (Exception e)
        {
            System.err.println("error in \
            IBMRssStorage \
            constructor [" + e.getMessage() + "]");
        }
    }
    public boolean closeStore()
    {
        try
        {
            store.closeRecordStore();
        }
        catch (Exception e)
        {
            System.err.println("Error closing [" + e.getMessage() + "]");
        }
        return true;
    }
    public int getNumRecords()
    {
        try
        {
            return store.getNumRecords();
        }
        catch (Exception e)
        {
            System.err.println("Error in getNumRecords " + e.getMessage());
            return 0;
        }
    }
    public byte[] getRecord(int recId)
    {
        try
        {
            return store.getRecord(recId);
        }
        catch (Exception e)
        {
            System.err.println("Error in getRecord[" + recId + "] " + e.getMessage());
            return null;
        }
    }

Los registros pueden ser enumerados según un criterio de filtros específicos o un orden de clasificación. Para enumerar los registros en una forma que no sea la ordinal, se necesita un RecordEnumeration. Se crea una RecordEnumeration llamando el método enumerateRecords de una instancia RecordStore. Los argumentos de este método incluyen un RecordFilter y un RecordComparator, ambos también forman parte del paquete javax.microedition.rms. Es algo común definir una clase específica de una aplicación que implementa ambas interfaces, como lo muestra la clase RssFilter en el Listado 4.

Listado 4. Clase RssFilter
public static class RSSFilter implements RecordFilter, RecordComparator 
    {
        private String _type = "";
        private String _name = "";
        
        RSSFilter(String type,String name)
        {
            _type = type;
            _name = name;
        }
        
        public boolean matches( byte[] recordData )
        {
            try
            {
                String oneRec = new String(recordData);
                Vector v1 = Utils.split(new String(recordData),"|");
                String recordType = (String) v1.elementAt(0);
                String recordName = (String) v1.elementAt(1);
                if (_name != null)   
                {
                    if (recordName.trim().equalsIgnoreCase(_name) &&
 			   recordType.equalsIgnoreCase(_type))
                    {
                        return true;
                    }
                }
                else
                {
                    // just matching type
                    if (recordType.equalsIgnoreCase(_type))
                    {
                        return true;
                    }
                }
            }
            catch (Exception e)
            {
                System.out.println(e);
                e.printStackTrace();
            }
            return false;
        }
        public int compare(byte[] rec1, byte[] rec2)
        {
            int comp = 0;
            try
            {
                String first = new String(rec1);
                String second = new String(rec2);
                Vector v1 = Utils.split(first,"|");
                Vector v2 = Utils.split(second,"|");
                if (_type.equals("H"))
                {
                    //compare name field
                    String r1 = ((String) v1.elementAt(1)).toUpperCase();
                    String r2 = ((String) v2.elementAt(1)).toUpperCase();
                    comp = r1.compareTo(r2);
                }
                else
                {
                    // compare title field
                    String r1 = ((String) v1.elementAt(2)).toUpperCase();
                    String r2 = ((String) v2.elementAt(2)).toUpperCase();
                    comp = r1.compareTo(r2);
                }
            }
            catch (Exception e)
            {                
            }
            if(comp < 0)
            {
                return PRECEDES;
            }
            else if( comp == 0 )
            {
                return EQUIVALENT;
            }
            else
            {
                return FOLLOWS;
            }
        }
     }

La interfaz RecordFilter queda satisfecha con el método matches. Cada registro debe ser dividido y ensamblado nuevamente para ser apareado y filtrado de forma apropiada. A veces un RecordFilter es utilizado para obtener una lista de registros de datos de cabecera y a veces para obtener todos los registros con un campo de nombre específico.

El RecordComparator es responsable por clasificar el orden. Emplea un algoritmo simple de comparación de textos para establecer una implementación de tipo alfa. Note el uso del método toUpperCase para hacer que la clasificación no distinga entre mayúsculas y minúsculas.

La clase IBMRssStorage contiene dos clases adicionales: cada una para representar RSS feeds y elementos RSS. Cada clase engloba análisis y manipulaciones a nivel campo con los métodos set y get apropiados. La clase IBMRssStorage también incluye varios métodos de ayuda o de fábrica para ayudar en la creación de las clases IBMRssFeed y IBMRssItem basándose en una variedad de datos de entrada. Las clases y ayudas se encuentran a continuación.

Listado 5. Clases IBMRssFeed e IBMRssItem
     public IBMRssFeed createFeed(String name,String url)
     {
         return new IBMRssFeed(name,url);
     }
     public IBMRssFeed createFeed(byte[] recordData)
     {
         return createFeed(new String(recordData));
     }
     public IBMRssFeed createFeed(String recordData)
     {
         Vector v = Utils.split(recordData,"|");
         IBMRssFeed feed = new IBMRssFeed();
         feed.setName((String) v.elementAt(1));
         feed.setUrl((String)v.elementAt(2));
         return feed;
     }
     public class IBMRssFeed
     {
         private String _name;
         private String _url;
         IBMRssFeed()
         {
         }
         IBMRssFeed(String name,String url)
         {
             _name = name;
             _url = url;
         }
         public String getName()
         {
             return _name;
         }
         
         public String getUrl()
         {
             return _url;
         }
          
          
         public void setName(String name)
         {
             _name = name;
         } 
         
         public void setUrl(String url)
         {
             _url = url;
         }
        
         public String toString()
         {
             String ret = "H|";
             ret += _name;
             ret += "|" + _url;
             return ret;
         }
     }
     
     public  IBMRssItem createItem(String name,String title,String link,
	  	String description,String category,String pubdate)
     {
         return new IBMRssItem(name,title,link,description,category,pubdate);
     }
     public IBMRssItem createItem(byte [] recordData)
     {
         return createItem(new String(recordData));
     }
     public  IBMRssItem createItem(String recordData)
     {
         Vector v = Utils.split(recordData,"|");
         IBMRssItem ret = new IBMRssItem();
         ret.setName((String) v.elementAt(1));
         ret.setTitle((String) v.elementAt(2));
         ret.setLink((String) v.elementAt(3));
         ret.setDescription((String) v.elementAt(4));
         ret.setCategory((String) v.elementAt(5));
         ret.setPubDate((String) v.elementAt(6));
         return ret;
     }
     public IBMRssItem createItem()
     {
        return new IBMRssItem();
     }
     public class IBMRssItem
     {
         private String _name = "";
         private String _title = "";
         private String _link = "";
         private String _description = "";
         private String _category = "";
         private String _pubDate = "";
         IBMRssItem()
         {
         }
         IBMRssItem(String name,String title,String link,
		String description,String category,String pubdate)
         {
             _name = name;
             _title = title;
             _link = link;
             _description = description;
             _category = category;
             _pubDate = pubdate;
         }
         public String getName()
         {
             return _name;
         }
         public String getTitle()
         {
             return _title;
         }
         public String getLink()
         {
             return _link;
         }
         public String getDescription()
         {
             return _description;
         }
         public String getCategory()
         {
             return _category;
         }
         public String getPubDate()
         {
             return _pubDate;
         }
         public void setName(String name)
         {
             _name = name;
         }
         public void setTitle(String title)
         {
             _title = title;
         }
         public void setLink(String link)
         {
             _link  = link;
         }
         public void setDescription(String description)
         {
             _description = description;
         }
         public void setCategory(String category)
         {
             _category = category;
         }
         public void setPubDate(String pubdate)
         {
             _pubDate = pubdate;
         }
         public String toString()
         {
             String ret = "D";
             ret += "|" + _name;
             ret += "|" + _title;
             ret += "|" + _link;
             ret += "|" + _description;
             ret += "|" + _category;
             ret += "|" + _pubDate;
             return ret;
         }
     }

Se utilizan los métodos toString, los cuales generan una representación lista para almacenar de los registros. Recuerde que en el lenguaje de programación Java, el método toString de cualquier objeto puede ser anulado para brindar una útil representación de los datos. Podría haber elegido el nombre de un método alternativo para cumplir con este paso de preparación para el almacenamiento.

Ahora que sabe a dónde y cómo se almacenan los datos, exploremos cómo obtenerlos desde Internet.

Comunicaciones

La clase IBMRssComms es responsable por recolectar los RSS feeds desde cada una de sus respectivas fuentes en Internet. Esta clase amplía la clase java.lang.Thread para que pueda funcionar independientemente del UI. La sección "Próximos pasos" trata acerca de los motivos para esta elección, pero por ahora examinemos el método run.

Listado 6. Recolectar datos de IBMRssComms
class IBMRssComms extends Thread
{
    IBMRssComms() 
    {
    }
    public void run()
    {
        InputStream inputStream = null;
        HttpConnection httpConnection = null;
        try
        {
            // open storage
            IBMRssStorage rss = new IBMRssStorage();
            
            // grab list of feeds
            RecordEnumeration feedList = rss.getFeedList();
            
            // process each
            while (feedList.hasNextElement())
            {
                IBMRssFeed theFeed = rss.createFeed(new String(feedList.nextRecord()));

                // delete any Items under this feed
                rss.deleteFeed(theFeed.getName(),true);
                
                // connect to feed's URL
                httpConnection = (HttpConnection)Connector.open(theFeed.getUrl());
                inputStream = httpConnection.openDataInputStream();
                
                // good connection?
                if(httpConnection.getResponseCode() == HttpConnection.HTTP_OK)
                {
                    // check header field for a specific encoding
                    String desiredEncoding = "ISO-8859-1";  //iso-8859-1
                    String contenttype = httpConnection.getHeaderField("Content-Type");
                    if (contenttype != null)
                    {
                        contenttype = contenttype.toUpperCase();
                        if (contenttype.indexOf("UTF-8") != -1)
                        {
                            desiredEncoding = "UTF-8";
                        }
                    }

                    // we need an input source for the sax parser
                    InputSource is = new InputSource(inputStream);

                    // setup Encoding to match what the Web server sent us
                    is.setEncoding(desiredEncoding);
                    
                    // create the factory
                    SAXParserFactory factory = SAXParserFactory.newInstance();
        
                    // create a parser
                    SAXParser parser = factory.newSAXParser();
                    
                    // instantiate our handler
                    IBMRssXMLHandler myHandler= new IBMRssXMLHandler(theFeed);

                    // perform the synchronous parse           
                    parser.parse(is,myHandler);
                }
            }
            
            // dump feeds to debug window
            rss.dumpFeeds();
            
            // close storage
            rss.closeStore();
        }
        catch (IOException ioe)
        {
            System.err.println("IO Exception !: " + ioe.getMessage());
            ioe.printStackTrace();
        }
        catch (SAXException saxe)
        {
            System.err.println("SAX Exception !: " + saxe.getMessage());
            saxe.printStackTrace();
        }
        catch (Exception e)
        {
            System.err.println("General Error " + e.getMessage());
            e.printStackTrace();
        }
        // notify gui that we're done!
        ApplicationManager.getApplicationManager().postGlobalEvent(Guid.rssdatadone,0,0); 
    }
}

La clase IBMRssComms enumera cada RSS feed disponible en la RecordStore (utilizando métodos IBMRssStorage) y trae los datos XML asociados a este. Los datos son analizados subsecuentemente por el analizador SAX XML parser y los datos almacenados en la RecordStore de forma apropiada. La clase HttpConnection se utiliza para obtener la secuencia de datos y su InputStream se utiliza para crear una InputSource. La InputSource es utilizada junto con una instancia de un tutorial de una clase de una aplicación de muestra para analizar los datos XML.

Los datos son analizados con la ayuda de la clase del IBMRssXMLHandler. Resulta interesante que esta sea la única clase en la totalidad de la aplicación que realmente conoce algo acerca de cómo subyace la estructura de datos RSS como se la recibe desde la fuente en Internet. El Listado 7 contiene esta clase, la cual amplía la clase DefaultHandler del paquete org.xml.sax.

Listado 7. Clase IBMRssXMLHandler.java
package com.msi.ibm.rssreader;
import org.xml.sax.helpers.*;
import org.xml.sax.*;
import java.lang.StringBuffer;
import com.msi.ibm.rssreader.IBMRssStorage.*;

class IBMRssXMLHandler extends DefaultHandler
{
    StringBuffer sb = null;
    IBMRssFeed _feed = null;
    IBMRssItem item = null;
    boolean bStarted = false;
    IBMRssStorage rssStore = null;
    IBMRssXMLHandler(IBMRssFeed feed) 
    {
        _feed = feed;
        rssStore = new IBMRssStorage();
    }
    public void warning(SAXParseException e) 
    {
        System.err.println("warning: " + e.getMessage());
        bStarted = false;
    }
    public void error(SAXParseException e) 
    {
        System.err.println("error: " + e.getMessage());
    }
    public void fatalError(SAXParseException e) 
    {
        System.err.println("fatalError: " + e.getMessage());
        bStarted = false;
    }
    public void startDocument() throws SAXException
    {
    }
    public void endDocument() throws SAXException
    {
        rssStore.closeStore();
    }
    public void startElement(String namespaceURI, String localName,
		String qName, Attributes atts) throws SAXException
    {
        sb = new StringBuffer("");
        if (localName.equals("item"))
        {
            bStarted = true;
            // new item, let's set up!
            item = rssStore.createItem();
        }
    }
    public void endElement(String namespaceURI, String localName,
		String qName) throws SAXException
    {
        if (bStarted == false) return;
        if (localName.equals("item"))
        {
            item.setName(_feed.getName());
            rssStore.addRecord(item); 
        }
        if (localName.equals("title"))
        {
            item.setTitle(sb.toString());
        }
        if (localName.equals("link"))
        {
            item.setLink(sb.toString());
        }
        if (localName.equals("description"))
        {
            item.setDescription(sb.toString());
        	    }
        if (localName.equals("category"))
        {
            item.setCategory(sb.toString());
        }
        if (localName.equals("pubDate"))
        {
            item.setPubDate(sb.toString());
        }                        
        sb = new StringBuffer("");
    }
    public void characters(char ch[], int start, int length)
    {
        String theString = new String(ch,start,length);
        sb.append(theString);
    }
}

Los métodos utilizados en la clase IBMRssXMLHandler son invocados por el motor de análisis SAX ya que algunos eventos ocurren y aparecen varias etiquetas. Por ejemplo, cuando aparece un startElement se inicia un nuevo IBMRssItem. A medida que se encuentra cada elemento, los datos son almacenados. Posteriormente, cuando sea encontrado el </item> campo, la clase sabe que un IBMRssItem completo se encuentra listo para ser almacenado.

Cuando se completa el ciclo de enumeración de cada feed, traer el origen de datos subyacente, analizar los datos y almacenar estos datos, la última línea de la clase IBMRssComms para el método run publica un evento global indicando que el proceso de actualización ha sido completado: ApplicationManager.getApplicationManager().postGlobalEvent(Guid.rssdatadone,0,0);.

El valor rssdatadone se encuentra definida en la clase Guid e implementada como un asociado final estático en Guid.java. Cuando se captura este evento, como se puede ver en la próxima sección, se actualiza el UI.

Se trae, analiza y almacena toda la información, entonces volvamos al examen de la UI.

La pantalla

La aplicación de ejemplo tiene un UI muy básico. La clase IBMRssScreen amplía la clase MainScreen, la cual es una clase ofrecida por RIM que implementa características comunes a las aplicaciones de BlackBerry. IBMRssScreen también implementa la interfaz Java ListFieldCallback y GlobalEventListener. La interfaz ListFieldCallback le permite a la clase reaccionar ante pedidos del UI para extraer los elementos en una ListField de control. La interfaz GlobalEventListener le permite al UI actualizarse luego de que un RSS feed ha sido recuperado de Internet. La figura 3 muestra la pantalla de la aplicación cuando se carga por primera vez incluyendo entradas pre cargadas de RSS feed.

Figura 3. IBMRssScreen muestra algunos RSS feeds disponibles
IBMRssScreen showing some available RSS feeds

El Listado 8 contiene el código de definiciones e inicialización UI.

Listado 8. Definiciones privadas de IBMRssScreen y el constructor
class IBMRssScreen extends MainScreen implements  ListFieldCallback, GlobalEventListener
{
    // private members - these represent the "controls"
    private LabelField statusField = null;
    private ListField feedList = null;
    private RecordEnumeration feeds = null;
    private int[] feedIds = null;
    private int[] itemIds = null;
    private int mode = 0;               // 0 is feeds, 1 is items
    private IBMRssStorage rss  = null;
    private MenuItem mnuRefreshFeeds = new MenuItem("Refresh Feeds", 100, 10) 
    {
        public void run() 
        {
            try
            {
                statusField.setText("Refreshing Feeds, Please Wait");
                feedList.setSize(0);
                IBMRssComms comms = new IBMRssComms();
                comms.start();
            }
            catch (Exception e)
            {
                System.err.println("Error Refresh Menu: " + e.getMessage());
                e.printStackTrace(); 
            }
        }
    };
    private MenuItem mnuSelectItem = new MenuItem("Select Item", 100, 10) 
    {
        public void run() 
        {
            try
            { 
                if (mode == 0)
                {
                    if (feedList.getSelectedIndex() >= 0)
                    {
                        loadFeed(feedList.getSelectedIndex());
                    }
                }
                else if (mode == 1)
                {
                    if (feedList.getSelectedIndex() >= 0)
                    {
                        showItem(feedList.getSelectedIndex());
                    }
                }
            }
            catch (Exception e)
            {
                System.err.println("Error Select Item Menu: " + e.getMessage());
                e.printStackTrace(); 
            }
        }
    };
    // constructor
    public IBMRssScreen()
    {
        // invoke the constructor of the super class (MainScreen)
        super();
        
        // give our application window a title
        setTitle("IBM Rss App");

        // setup our storage system
        rss = new IBMRssStorage();
        
        if (rss.getNumRecords() == 0)
        {
           
            IBMRssFeed myFeedDevSource = rss.createFeed("DevSource",
		 "http://feeds.ziffdavisenterprise.com/RSS/devsource.xml");
             rss.addRecord(myFeedDevSource);
            
            IBMRssFeed myFeedIBM = rss.createFeed("Developerworks",
		 "http://www.ibm.com/developerworks/views/opensource/
		 rss/libraryview.jsp");
             rss.addRecord(myFeedIBM);
            
            IBMRssFeed myFeedNY = rss.createFeed("New Yorker",
		 "http://xml.newsisfree.com/feeds/76/13276.xml");
             rss.addRecord(myFeedNY);
            
            IBMRssFeed myFeedAIG = rss.createFeed("Answers In Genesis",
		 "http://www.answersingenesis.org/store/rss/newest");
             rss.addRecord(myFeedAIG);
            
            IBMRssFeed myFeed = rss.createFeed("Handango BB Apps",
		 "http://service.handango.com/ampp/ContentRequestGenerator?
		 id=123&password=rss20content&platformId=5
		 &maxCount=50&optionId=1");
             rss.addRecord(myFeed);
        }

        // display the fields in debug window
        //rss.dumpFeeds();
        
        // create user interface components
        createui();

        // load the data
        setupdata();

        // add listeners
        addKeyListener(new RssKeyListener());
        UiApplication.getUiApplication().addGlobalEventListener(this);
    }

Los dos menús que la aplicación necesita son definidos como asociados de clase o nivel privado del tipo MenuItem. Después de invocar el método super() para inicializar la superclase y configurar un título, la capa persistente de almacenamiento se configura con una instancia de clase IBMRssStorage.

Algunos feeds de muestra son agregados si no se encuentra ninguno en la RecordStore. La línea comentada rss.dumpFeeds() es un método de ayuda para mostrar el contenido almacenado en la ventana JDE de salida. Una llamada al método createui agrega los elementos UI a la pantalla el método setupdata provoca que los datos se rellenen en el UI.

Listado 9. Métodos createui y setupdata
    private void createui()
    {
        try
        {
            addMenuItem(mnuRefreshFeeds);
            addMenuItem(mnuSelectItem);
              
            statusField = new LabelField("Select a Feed Below");
            add(statusField);
            add(new SeparatorField());
            feedList= new ListField();
            feedList.setCallback(this);
            add(feedList);
            
        }
        catch (Exception e)
        {
            System.out.println("Failed to create user interface components");
        }
    }

    private void setupdata()
    {
        mode = 0;
        feeds = rss.getFeedList();
        feedIds = new int[feeds.numRecords()];
        int i = 0;
        try
        {
            while (feeds.hasNextElement())
            {
                feedIds[i++] = feeds.nextRecordId();
            }
        }
        catch (Exception e)
        {
            System.err.println("Error enumerating Feeds " + e.getMessage());
        }
        statusField.setText("Select a Feed Below");
        feedList.setSize(feeds.numRecords());
        feedList.invalidate();
    }

Entonces el constructor agrega KeyListener y un GlobalEventListener a esta pantalla. El KeyListener es implementado por RssKeyListener mientras que la interfaz GlobalEventListener queda satisfecha con la clase IBMRssScreen.

Los menús son agregados a la pantalla con el método addMenuItem. Los demás controles son añadidos a la MainScreen con el método add. La MainScreen implementa un solo VerticalManager para que cada campo o control agregado simplemente se apile uno sobre otro de forma vertical.

Cuando lo selecciona, mnuRefreshFeeds borra ListField configurando su tamaño a 0, luego crea una instancia de IBMRssComms, la cual es reiniciada luego. Mientras se ejecuta el subproceso de IBMRssComms, la UI le notifica al usuario que algo sucede y que no debe preocuparse.

Figura 4. Actualización de los datos RSS feeds
Application refreshing RSS data feeds

Una vez que todos los RSS feeds han sido actualizados, se publica un evento que es capturado por el método de IBMRssScreen llamado eventOccurred. Recuerde, esta clase implementa la interfaz GlobalEventListener.

Listado 10. Implementación de la interfaz GlobalEventListener
public void eventOccurred( long guid, int data0, \
int data1, Object object0, Object object1) 
{
   if (guid == Guid.rssdatadone)
   {
        setupdata();
   }
}

Ahora que toda la información ha sido actualizada, examine cómo aparece en la pantalla ListField. El Listado 11 muestra dos de los métodos requeridos por la interfaz ListFieldCallback.

Listado 11. Implementación de la interfaz ListFieldCallback
    public void drawListRow(ListField listField,Graphics \
    graphics,int index,int y,int width)
    {
        graphics.setFont(Font.getDefault());
        if (mode == 0)
        {
            IBMRssFeed thisFeed = rss.createFeed(rss.getRecord(feedIds[index]));
            graphics.drawText(thisFeed.getName(),2,y,DrawStyle.TOP,width);
        }
        else
        {
            IBMRssItem thisItem = rss.createItem(rss.getRecord(itemIds[index]));
            graphics.drawText(thisItem.getTitle(),2,y,DrawStyle.TOP,width);
        }
    }

    public int getPreferredWidth(ListField listField)    
    {
        return Graphics.getScreenWidth();
    }

El método getPreferredWidth es bastante sencillo; sólo se centra en lo amplia que debería ser la lista. El trabajo real se lleva a cabo en el método drawListRow, que utiliza los argumentos revisados para determinar cuáles son los datos que debe proveer. En la aplicación de muestra, el asociado variable privado de nombre mode determina si ListField muestra los feeds o los elementos de un feed en particular. Puede ver esto claramente drawListRow a medida que el método recupera los datos de los elementos apropiados y utiliza la instancia gráfica para extraer el texto con el método drawText.

Existen dos conjuntos completos que son utilizados para registrar los ID para un acceso más rápido a un registro particular. Los conjuntos son actualizados cada vez que se selecciona un nuevo RSS feed. El código para gestionar los feedIds se encuentra ubicado en el método setupdata. El código para gestionar los itemIds se encuentra en el método loadFeed.

Listado 12. Método loadFeed almacena los ID
   private void loadFeed(int feedIndex)
    {
        IBMRssFeed thisFeed = rss.createFeed(rss.getRecord(feedIds[feedIndex]));

        statusField.setText(thisFeed.getName());

        RecordEnumeration items = rss.getFeedItems(thisFeed.getName());
        itemIds = new int[items.numRecords()];
        int i = 0;
        try
        {
            while (items.hasNextElement())
            {
                itemIds[i++] = items.nextRecordId();
            }
        }
        catch (Exception e)
        {
            System.err.println("Error enumerating items in feed [" +
		 thisFeed.getName() + "] " + e.getMessage());
        }
        mode = 1;
        if (items.numRecords() > 0)
        {
            feedList.setSelectedIndex(0);
        }
        feedList.setSize(items.numRecords());
        feedList.invalidate();
    }

Cuando se selecciona un elemento, se invoca el método showItem, el cual crea una instancia de IBMRssDescription, que es una clase incluida en IBMRssScreen. La Figura 5 muestra la pantalla en acción.

Figura 5. Cómo seleccionar un elemento de un feed
Selecting an item from a feed

Cuando se selecciona Full Story, el enlace del elemento se abre en el buscador del BlackBerry con un código de línea simple: Browser.getDefaultSession().displayPage(_item.getLink());.

Cómo ejecutar la aplicación

A esta altura, ya ha revisado todos los fragmentos de código importantes y es hora de construir y probar la aplicación. Si es nuevo con los desarrollos de BlackBerry y necesita algo de ayuda para construir una aplicación en JDE, vea los Recursos.

Si asumimos que la aplicación fue construida sin errores, puede ejecutarla en el simulador de BlackBerry:

  1. Asegúrese de que el simulador MDS se encuentre en funcionamiento. El simulador MDS le permite al simulador BlackBerry conectarse a la red, incluyendo Internet.
  2. Si selecciona la tecla F5 se ejecuta el simulador BlackBerry.
  3. El tutorial de la aplicación de muestra no comenzará a funcionar de inmediato. Para que comience, navegue hacia el ícono de la página de inicio de la cinta de la aplicación y seleccione el tutorial de la aplicación de muestra, conocida como IBMRssReader, con el ícono RSS como se puede ver a continuación. Las teclas de flecha en la computadora simulan la distancia entre las ruedas, la tecla Enter simula presionar la rodadura y la tecla Esc emula el botón Esc del BlackBerry.
Figura 6. IBMRssReader en el simulador BlackBerry
IBMRssReader on the BlackBerry simulator

¡La aplicación ha sido desarrollada! Siéntase libre de ejecutar la aplicación y experimente con diferentes RSS feeds.


Próximos pasos

Debemos mencionar algunos elementos adicionales antes de concluir.

Cómo manejar errores

Para una mayor brevedad y claridad, en este tutorial se omite la sección en la que se explica cómo manejar los errores. Por supuesto que cualquier código de producción listo debería tener una saludable dosis acerca de cómo manejar los errores al igual que de instrucciones para el usuario en caso que algo se encuentre fuera de lugar.

Por necesidad se ha incluido el manejo de errores en la clase IBMRssXMLHandler. Note la implementación de los métodos error y fatalerror. Si nuestro manejador no implementa estos métodos y nos encontramos con un error, el proceso de análisis fallará por completo. En este caso, cualquier elemento que contenga datos inválidos será simplemente ignorado en el feed. La aplicación puede continuar y procesar los datos como mejor pueda sin tener que lidiar con errores muy graves problemáticos que traen como resultado la pérdida de todos los datos de feed cuando quizá solo había una sola entrada ofensiva.

Actualizaciones automáticas

La clase IBMRssComms fue implementada como una extensión de java.lang.Thread. Para obtener un lector RSS listo para producción es provechoso contar con los datos actualizados de forma planificada o automatizada. Cuando se levanta de la cama a la mañana y busca su BlackBerry, puede tener las novedades e información más recientes en su lector RSS. Puede convertir la aplicación en un módulo de sistema y configurar un temporizador para invocar la clase IBMRssComms a un horario conveniente. Si implementa esta clase como un subproceso, puede hacer su trabajo en segundo plano sin interferir con otros usos de la aplicación.


Resumen

En este tutorial exploró el formato de datos RSS y creó una aplicación BlackBerry para procesar, gestionar y mostrar los datos para aplicaciones de una forma tan simple y útil como un nuevo lector. También se sugirieron usos alternativos para datos RSS y para su BlackBerry. Aprendió acerca de cómo los temas fundamentales de desarrollo BlackBerry, incluyendo recuperación de datos HTTP, análisis XML, almacenamiento y recuperación de registros. También pudo ver cómo ListField puede ser una construcción flexible de la representación de datos. La nivelación de la tecnología de código abierto de la tecnología Java y RSS posee un gran potencial para brindarle valor al comercio vertical y a las aplicaciones para los consumidores.


Descargar

DescripciónNombretamaño
RSS reader source codeos-blackberry2-IBMRssReader_src.zip113KB

Recursos

Aprender

  • Lea la Parte 1 de esta serie, la cual sienta las bases para una aplicación que colecte datos de códigos abiertos sobre los cuales se construirá una servicio de recolección de datos fácil de usar.
  • BlackBerry Desktop Software: Research In Motion (RIM) ofrece un rango de información de usuario y de administrador acerca del BlackBerry Desktop Software, incluyendo más acerca de cómo instalar un software a través del Desktop Manager.
  • Encontrará artículos acerca de cualquier aspecto de la programación Java en developerWorks zona tecnológica Java.
  • OpenSource.org presenta un catálogo de las licencias de código abierto más populares.
  • Aprenda más acerca de la historia de RSS desde Harvard Law.
  • Para escuchar entrevistas interesantes y discusiones para los desarrolladores de software, pruebe developerWorks podcasts.
  • Manténgase actualizado con Technical events and webcasts de developerWorks.
  • Siga a developerWorks en Twitter.
  • Consulte las próximas conferencias, los shows comerciales, los webcasts y otros Eventos de todo el mundo que son de interés para los desarrolladores de código abierto de IBM.
  • Visite la Open source zone de developerWorks para obtener información exhaustiva sobre instrucciones, herramientas y de proyectos para ayudarlo a desarrollarse con las tecnologías de códigos abiertos y a utilizarlos con los productos de IBM.
  • Vea y aprenda acerca de funciones de productos y tecnologías IBM y de código abierto con el developerWorks On demand demos gratuitos.

Obtener los productos y tecnologías

Comentar

Comentarios

developerWorks: Ingrese

Los campos obligatorios están marcados con un asterisco (*).


¿Necesita un IBM ID?
¿Olvidó su IBM ID?


¿Olvidó su Password?
Cambie su Password

Al hacer clic en Enviar, usted está de acuerdo con los términos y condiciones de developerWorks.

 


La primera vez que inicie sesión en developerWorks, se creará un perfil para usted. La información en su propio perfil (nombre, país/región y nombre de la empresa) se muestra al público y acompañará a cualquier contenido que publique, a menos que opte por la opción de ocultar el nombre de su empresa. Puede actualizar su cuenta de IBM en cualquier momento.

Toda la información enviada es segura.

Elija su nombre para mostrar



La primera vez que inicia sesión en developerWorks se crea un perfil para usted, teniendo que elegir un nombre para mostrar en el mismo. Este nombre acompañará el contenido que usted publique en developerWorks.

Por favor elija un nombre de 3 - 31 caracteres. Su nombre de usuario debe ser único en la comunidad developerWorks y debe ser distinto a su dirección de email por motivos de privacidad.

Los campos obligatorios están marcados con un asterisco (*).

(Por favor elija un nombre de 3 - 31 caracteres.)

Al hacer clic en Enviar, usted está de acuerdo con los términos y condiciones de developerWorks.

 


Toda la información enviada es segura.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=90
Zone=
ArticleID=857691
ArticleTitle=Creación de aplicaciones para BlackBerry con herramientas de código abierto, parte 2: Cómo construir un lector RSS
publish-date=02112013