 | 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
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.
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.
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.
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
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
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
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());.
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:
- 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.
- A seleção da tecla
F5 iniciará o simulador do BlackBerry.
- 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
O aplicativo está construído! Fique à vontade para executar o aplicativo e experimentá-lo com diferentes feeds RSS.
|  |