Avançar para a área de conteúdo

ir para o conteúdo principal

developerWorks Brasil  >  Software livre  >

Crie Aplicativos BlackBerry com Ferramentas de Software Livre, Parte 2: Construindo um Leitor de RSS

developerWorks
Ir para a página anteriorPágina 3 de 9 Ir para a próxima página

Opções de documento

Código de amostra


Classificar este tutorial

Ajude-nos a melhorar este conteúdo


Criando o Leitor de RSS BlackBerry

A melhor maneira de se aprender é fazendo, então, vamos começar. Esta seção examina cada um dos principais elementos do aplicativo de amostra do tutorial, incluindo os snippets de código de origem relevantes.

A Estrutura do Aplicativo

Você vai criar um único aplicativo, parte por parte, neste tutorial. Você pode fazer o download do código fonte completo. A Figura 2 mostra os arquivos de origem no aplicativo de amostra.


Figura 2. Arquivo de Projeto no BlackBerry JDE
Arquivo de Projeto no BlackBerry JDE

O primeiro trecho de código a ser revisado está em IBMRssApplication.java. Como em qualquer aplicativo Java, um aplicativo requer um ponto de entrada, como main no arquivo IBMRssApplication.java.


Listagem 2. Método Main do Arquivo IBMRssApplication.java

//
// IBMRssApplication.java
//
// MSI Services, Inc.
// Frank Ableson
// 973.448.0070
// fableson@msiservices.com
// código livre para uso para qualquer propósito, seja comercial ou não

package com.msi.ibm.rssreader;

// importações necessárias
import net.rim.device.api.ui.*;

// nosso aplicativo
class IBMRssApplication extends UiApplication
{
    // ponto de entrada do aplicativo
    public static void main(String[] args)
    {
        // crie uma instância do aplicativo
        IBMRssApplication theApp = new IBMRssApplication();
        // "execute" o aplicativo
        theApp.enterEventDispatcher();
    }
    // construtor do aplicativo
    public IBMRssApplication()
    {
        // crie uma instância da tela principal do aplicativo
        IBMRssScreen screen = new IBMRssScreen();
        // deixe a tela visível
        UiApplication.getUiApplication().pushScreen(screen);
    }
}

O método main cria uma nova instância da classe IBMRssApplication, que é uma extensão da classe UiApplication. UiApplication está localizado no pacote net.rim.device.api.ui. A classe UiApplication é uma classe base para todos os aplicativos BlackBerry que têm uma UI.

O construtor da classe IBMRssApplication cria uma instância da classe IBMRssScreen. Essa classe é definida e implementada no IBMRssScreen.java. Após a instância de IBMRssScreen ser criada, ela é passada para o método pushScreen(). Essencialmente, isso traz a tela para a visualização no dispositivo.

Antes de explorar a UI do aplicativo, existem alguns aspectos importantes do código que devem ser considerados. A UI conta muito com as funções contidas em outras classes.



Voltar para parte superior


Armazenamento Persistente

O armazenamento de dados e a organização são cruciais para muitos aplicativos e o aplicativo de amostra neste tutorial não é uma exceção. A classe IBMRssStorage implementada no IBMRssStorage.java é responsável pelo gerenciamento de dados para o aplicativo de amostra. Dados são armazenados em um RecordStore, que pode ser localizado no pacote javax.microedition.rms. A classe IBMRssStorage possui inúmeros métodos auxiliares para a manipulação de registros armazenados e três classes contidas, que representam constructos importantes para o aplicativo.

Dados são armazenados em um RecordStore como uma série de arrays de byte de comprimento variável de acesso aleatório. O aplicativo de amostra deste tutorial utiliza um único RecordStore contendo dois tipos de registros distintos: um registro de cabeçalho que representa um feed RSS e um registro de detalhes que representa um item de RSS. Quando dados de RSS são processados pelo aplicativo, eles são segregados nesses dois tipos de registros e persistem. Essa abordagem foi selecionada porque em um aplicativo customizado, podem existir mais elementos de dados incluídos (ou subtraídos) além do formato de dados de RSS de base utilizado na distribuição de dados.

O armazenamento apenas dos dados necessários deixa o aplicativo com a memória mais eficiente e fornece acesso mais rápido aos dados. Para conservar espaço, todos os registros são armazenados como strings delimitadas por barras em pé. A classe Utils, implementada em Utils.java, contém o método split, que é utilizado em partes do código para facilitar a manipulação desses registros analisando-os e colocando os elementos de dados individuais nos elementos de uma instância java.util.Vector.

A estrutura de um registro de Cabeçalho é H | Nome do Feed | URL para a Origem do Feed | Data de Publicação. O registro de detalhes é definido como D | Nome do Feed | Título do Item | Link para Histórico Completo | Descrição | Data de Publicação.

A Listagem 3 mostra partes da classe IBMRssStorage responsável por abrir e fechar RecordStore e dois métodos auxiliares para a recuperação de registros.


Listagem 3. Snippet da Classe 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;
        }
    }

Registros podem ser enumerados de acordo com um critério de filtragem específico na ordem de classificação. Para enumerar registros de qualquer maneira que não seja a ordinal, RecordEnumeration é necessário. Um RecordEnumeration é criado chamando-se o método enumerateRecords de uma instância RecordStore. Os argumentos para este método incluem um RecordFilter e um RecordComparator, que também fazem parte do pacote javax.microedition.rms. Essa é uma prática comum para se definir uma classe específica de aplicativo que implementa ambas as interfaces, conforme mostrado na classe RssFilter na Listagem 4.


Listagem 4. Classe 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
                {
                    // apenas tipo de correspondência
                    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"))
                {
                    //comparar campo de nome
                    String r1 = ((String) v1.elementAt(1)).toUpperCase();
                    String r2 = ((String) v2.elementAt(1)).toUpperCase();
                    comp = r1.compareTo(r2);
                }
                else
                {
                    // comparar campo de título
                    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;
            }
        }
     }

A interface RecordFilter é satisfeita com o método de correspondências. Cada registro deve ser dividido e remontado para ser corretamente correspondido e filtrado. Às vezes, um RecordFilter é empregado para se obter uma lista apenas dos registros de cabeçalho e às vezes para se obter todos os registros com um determinado campo de nome.

O RecordComparator é responsável pela ordem de classificação. Ele emprega um algoritmo de comparação de string simples para estabelecer uma implementação de classificação por ordem alfabética. Observe o uso do método toUpperCase para que a classificação faça distinção entre maiúsculas e minúsculas.

A classe IBMRssStorage contém duas classes adicionais: uma para representar RSS feeds e uma para itens de RSS. Cada classe encapsula análise e manipulações de nível de campo com os métodos set e get apropriados. A classe IBMRssStorage também inclui vários métodos auxiliares, ou de factory, para ajudar na criação das classes IBMRssFeed e IBMRssItem com base em uma variedade de dados de entrada. As classes e os auxiliares são mostrados abaixo.


Listagem 5. Classes 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;
         }
     }

Os métodos toString, que geram uma representação pronta para armazenamento, são utilizados. Lembre-se de que na linguagem de programação Java, o método toString de qualquer objeto pode ser substituído para fornecer uma representação útil dos dados. Você poderia ter escolhido um nome de método alternativo para realizar esta etapa de preparação de armazenamento.

Agora que você sabe onde e como os dados são armazenados, vamos explorar como obtê-los da Internet.



Voltar para parte superior


Comunicações

A classe IBMRssComms é responsável por buscar os feeds RSS de cada uma de suas respectivas origens na Internet. Essa classe estende a classe java.lang.Thread para que ela possa ser executada independentemente da UI. A seção "Próximas Etapas" discute algumas lógicas para esta opção, mas por enquanto, vamos examinar o método run.


Listagem 6. IBMRssComms — Buscando Dados

class IBMRssComms extends Thread
{
    IBMRssComms()
    {
    }
    public void run()
    {
        InputStream inputStream = null;
        HttpConnection httpConnection = null;
        try
        {
            // abrir armazenamento
            IBMRssStorage rss = new IBMRssStorage();

            // pegar lista de feeds
            RecordEnumeration feedList = rss.getFeedList();

            // processar cada
            while (feedList.hasNextElement())
            {
                IBMRssFeed theFeed = rss.createFeed(new String(feedList.nextRecord()));

                // excluir quaisquer Itens neste feed
                rss.deleteFeed(theFeed.getName(),true);

                // conectar à URL do feed
                httpConnection = (HttpConnection)Connector.open(theFeed.getUrl());
                inputStream = httpConnection.openDataInputStream();

                // boa conexão?
                if(httpConnection.getResponseCode() == HttpConnection.HTTP_OK)
                {
                    // verifique o campo de cabeçalho para uma codificação específica
                    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";
                        }
                    }

                    // uma origem de entrada é necessária para o analisador sax
                    InputSource is = new InputSource(inputStream);

                    // configure a Codificação para corresponder ao que foi enviado pelo servidor da Web
|-------10--------20--------30--------40--------50--------60--------70--------80--------9|
|-------- Erro XML:  A linha anterior não é maior do que o máximo de 90 caracteres ---------|
                    is.setEncoding(desiredEncoding);

                    // crie o factory
                    SAXParserFactory factory = SAXParserFactory.newInstance();

                    // crie um analisador
                    SAXParser parser = factory.newSAXParser();

                    // instancie o manipulador
                    IBMRssXMLHandler myHandler= new IBMRssXMLHandler(theFeed);

                    // execute a análise síncrona
                    parser.parse(is,myHandler);
                }
            }

            // dump feeds para janela de depuração
            rss.dumpFeeds();

            // fechar armazenamento
            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();
        }
        // notificar gui de que está tudo pronto!
        ApplicationManager.getApplicationManager().postGlobalEvent(Guid.rssdatadone,0,0);
    }
}

A classe IBMRssComms enumera cada RSS feed disponível em RecordStore (utilizando métodos IBMRssStorage) e busca dados XML associados a ele. Esses dados são analisados subsequentemente pelo analisador SAX e os dados são armazenados no RecordStore da forma apropriada. A classe HttpConnection é utilizada para se obter o fluxo de dados, e seu InputStream é utilizado para criar o InputSource. Esse InputSource é utilizado, junto com uma instância de uma classe de aplicativo de amostra do tutorial, para analisar os dados XML.

Os dados são analisados com a ajuda da classe IBMRssXMLHandler. O mais interessante é que esta é a única classe no aplicativo inteiro que sabe de verdade tudo sobre a estrutura de dados RSS subjacente e como ela é recebida da origem da Internet. A Listagem 7 contém essa classe, que estende a classe DefaultHandler a partir do pacote org.xml.sax.


Listagem 7. Classe 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;
            // novo item, vamos configurá-lo!
            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);
    }
}

Os métodos na classe IBMRssXMLHandler são chamados pelo mecanismo de análise SAX conforme certos eventos ocorrem e várias tags são encontradas. Por exemplo, quando startElement é encontrado, um novo IBMRssItem é inicializado. Conforme cada elemento do item é encontrado, dados são armazenados. Subsequentemente, quando o campo </item> é encontrado, a classe sabe que um IBMRssItem completo está pronto para ser armazenado.

Quando o ciclo completo de enumeração de cada feed, de busca da origem de dados subjacente, de análise dos dados e de armazenamento desses dados estiver completo, a última linha do método run da classe IBMRssComms postará um evento global indicando que o processo de atualização de dados está completo: ApplicationManager.getApplicationManager().postGlobalEvent(Guid.rssdatadone,0,0);.

O valor rssdatadone é definido na classe Guid e implementado como um membro final estático em Guid.java. Quando esse evento for capturado, conforme visto na próxima seção, a UI será atualizada.

Todos os dados foram buscados, analisados e armazenados, então vamos voltar a examinar a UI.



Voltar para parte superior


A Tela

O aplicativo de exemplo possui uma UI super básica. A classe IBMRssScreen estende a classe MainScreen, que é uma classe fornecida por RIM que implementa recursos comuns para aplicativos BlackBerry. IBMRssScreen também implementa ListFieldCallback e GlobalEventListener da interface Java. A interface ListFieldCallback permite que a classe reaja aos pedidos feitos pela UI para desenhar itens em um controle ListField. A interface GlobalEventListener permite que a UI seja atualizada após um novo feed RSS ter sido recuperado da Internet. A Figura 3 mostra a tela do aplicativo quando ele é carregado pela primeira vez, incluindo algumas entradas de feed RSS pré-carregadas.


Figura 3. IBMRssScreen mostrando alguns feeds RSS disponíveis
IBMRssScreen mostrando alguns feeds RSS disponíveis

A Listagem 8 contém as definições de UI e o código de inicialização.


Listagem 8. Definições Privadas de IBMRssScreen e o Construtor

class IBMRssScreen extends MainScreen implements  ListFieldCallback, GlobalEventListener
{
    // membros privados - representam os "controles"
    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 representa feeds, 1 representa itens
    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();
            }
        }
    };
    // construtor
    public IBMRssScreen()
    {
        // chame o construtor da superclasse (MainScreen)
        super();

        // dê um título à janela de aplicativo
        setTitle("IBM Rss App");

        // configure o sistema de armazenamento
        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);
        }

        // exiba os campos na janela de depuração
        //rss.dumpFeeds();

        // crie componentes da interface com o usuário
        createui();

        // carregue os dados
        setupdata();

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

Os dois menus requeridos pelo aplicativo são definidos como membros de nível de classe privada do tipo MenuItem. Após chamar o método super() para inicializar a superclasse e configurar um título, a camada de armazenamento persistente é configurada com uma instância da classe IBMRssStorage.

Alguns feeds de amostra serão incluídos se nenhum for localizado em RecordStore. A linha comentada rss.dumpFeeds() é um método auxiliar para a exibição do conteúdo de armazenamento para a janela de saída do JDE. Uma chamada para o método createui inclui os elementos de UI na tela e o método setupdata faz os dados serem preenchidos na UI.


Listagem 9. Métodos createui e 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();
    }

Então o construtor inclui um KeyListener e um GlobalEventListener nesta tela. O KeyListener é implementado por RssKeyListener enquanto a interface GlobalEventListener é satisfeita pela classe IBMRssScreen em si.

Os menus são incluídos na tela com o método addMenuItem. Os outros controles são incluídos no MainScreen com o método add. O MainScreen implementa um único VerticalManager para que cada campo ou controle fique empilhado sob o outro verticalmente.

Quando selecionado, mnuRefreshFeeds limpa o ListField configurando seu tamanho para 0 e cria uma instância de IBMRssComms, que é iniciada. Enquanto o encadeamento IBMRssComms estiver em execução, a UI dirá ao usuário que algo está acontecendo e para ele se preparar.


Figura 4. Aplicativo Atualizando Alimentações de Dados de RSS
Aplicativo Atualizando Alimentações de Dados de RSS

Quando todos os feeds RSS forem atualizados, será postado um evento que é capturado pelo método eventOccurred da IBMRssScreen. Lembre-se, essa classe implementa a interface GlobalEventListener.


Listagem 10. Implementação da Interface GlobalEventListener

public void eventOccurred( long guid, int data0, \
int data1, Object object0, Object object1)
{
   if (guid == Guid.rssdatadone)
   {
        setupdata();
   }
}

Agora que você tem todos os dados atualizados, examine como eles serão exibidos de fato na tela em ListField. A Listagem 11 mostra dois dos métodos requeridos pela interface ListFieldCallback.


Listagem 11. Implementação da Interface 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();
    }

O método getPreferredWidth é totalmente direto; sua única preocupação é o tamanho da lista que será desenhada. O verdadeiro trabalho acontece no método drawListRow, que utiliza os argumentos passados para se determinar quais dados fornecer. No aplicativo de amostra, a variável de membro privada denominada mode determina se ListField está exibindo os feeds ou os itens de um determinado feed. Isso pode ser visto claramente em drawListRow conforme o método recupera o elemento de dados apropriado e utiliza a instância de gráfico para desenhar o texto com o método drawText.

Existem duas arrays de números inteiros para armazenar em cache os IDs de registro para rápido acesso a um determinado registro. As arrays são atualizadas cada vez que um novo feed RSS é selecionado. O código para gerenciar feedIds pode ser localizado no método setupdata. O código para gerenciar itemIds está no método loadFeed.


Listagem 12. Método loadFeed Armazena em Cache IDs de Registro

   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();
    }

Quando um item é selecionado, o método showItem é chamado, o que cria uma instância de IBMRssDescription, que é uma classe contida de IBMRssScreen. A Figura 5 mostra esta tela em ação.


Figura 5. Selecionando um Item de um Feed
Selecionando um Item de um Feed

Quando o Histórico Completo é selecionado, o link do item é aberto no navegador BlackBerry com uma única linha de código: Browser.getDefaultSession().displayPage(_item.getLink());.



Voltar para parte superior


Executando o Aplicativo

Neste ponto, você revisou todos os trechos de código importantes e agora é hora de construir e testar o aplicativo. Se você for novo no desenvolvimento do BlackBerry e precisar de ajuda para construir um aplicativo no JDE, consulte Recursos.

Supondo-se que o aplicativo tenha sido construído sem erros, você pode executá-lo no simulador do BlackBerry:

  1. Certifique-se de que o Simulador MDS esteja em execução. O simulador MDS permite que o simulador do BlackBerry se conecte à rede, incluindo a Internet.
  2. A seleção da tecla F5 iniciará o simulador do BlackBerry.
  3. O aplicativo de amostra do tutorial não será iniciado imediatamente. Para iniciá-lo, navegue para o ícone do aplicativo na faixa do aplicativo de página inicial e selecione o aplicativo de amostra do tutorial, chamado IBMRssReader, com o ícone RSS conforme mostrado abaixo. As teclas de seta no computador simulam o trackwheel, a tecla Enter simula o pressionamento do trackwheel e a tecla Esc emula o botão Esc do BlackBerry.


Figura 6. IBMRssReader no Simulador do BlackBerry
IBMRssReader no Simulador do BlackBerry

O aplicativo está construído! Fique à vontade para executar o aplicativo e experimentá-lo com diferentes feeds RSS.



Voltar para parte superior



Ir para a página anteriorPágina 3 de 9 Ir para a próxima página