projeto jedi - desenvolvimento de aplicações móveis - java - 164 páginas

164
Módulo 5 Desenvolvimento de Aplicações Móveis Lição 1 Introdução Versão 1.0 - Set/2007

Upload: augustonunes

Post on 15-Jun-2015

440 views

Category:

Documents


6 download

TRANSCRIPT

Page 1: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

Módulo 5Desenvolvimento de Aplicações Móveis

Lição 1Introdução

Versão 1.0 - Set/2007

Page 2: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

AutorA. Oliver de Guzman

EquipeRommel FeriaJohn Paul Petines

Necessidades para os ExercíciosSistemas Operacionais SuportadosNetBeans IDE 5.5 para os seguintes sistemas operacionais:

• Microsoft Windows XP Profissional SP2 ou superior• Mac OS X 10.4.5 ou superior• Red Hat Fedora Core 3 • Solaris™ 10 Operating System (SPARC® e x86/x64 Platform Edition)

NetBeans Enterprise Pack, poderá ser executado nas seguintes plataformas:• Microsoft Windows 2000 Profissional SP4• Solaris™ 8 OS (SPARC e x86/x64 Platform Edition) e Solaris 9 OS (SPARC e

x86/x64 Platform Edition) • Várias outras distribuições Linux

Configuração Mínima de HardwareNota: IDE NetBeans com resolução de tela em 1024x768 pixel

Sistema Operacional Processador Memória HD Livre

Microsoft Windows 500 MHz Intel Pentium III workstation ou equivalente

512 MB 850 MB

Linux 500 MHz Intel Pentium III workstation ou equivalente

512 MB 450 MB

Solaris OS (SPARC) UltraSPARC II 450 MHz 512 MB 450 MB

Solaris OS (x86/x64 Platform Edition)

AMD Opteron 100 Série 1.8 GHz 512 MB 450 MB

Mac OS X PowerPC G4 512 MB 450 MB

Configuração Recomendada de Hardware

Sistema Operacional Processador Memória HD Livre

Microsoft Windows 1.4 GHz Intel Pentium III workstation ou equivalente

1 GB 1 GB

Linux 1.4 GHz Intel Pentium III workstation ou equivalente

1 GB 850 MB

Solaris OS (SPARC) UltraSPARC IIIi 1 GHz 1 GB 850 MB

Solaris OS (x86/x64 Platform Edition)

AMD Opteron 100 Series 1.8 GHz 1 GB 850 MB

Mac OS X PowerPC G5 1 GB 850 MB

Requerimentos de SoftwareNetBeans Enterprise Pack 5.5 executando sobre Java 2 Platform Standard Edition Development Kit 5.0 ou superior (JDK 5.0, versão 1.5.0_01 ou superior), contemplando a Java Runtime Environment, ferramentas de desenvolvimento para compilar, depurar, e executar aplicações escritas em linguagem Java. Sun Java System Application Server Platform Edition 9.

• Para Solaris, Windows, e Linux, os arquivos da JDK podem ser obtidos para sua plataforma em http://java.sun.com/j2se/1.5.0/download.html

• Para Mac OS X, Java 2 Plataform Standard Edition (J2SE) 5.0 Release 4, pode ser obtida diretamente da Apple's Developer Connection, no endereço: http://developer.apple.com/java (é necessário registrar o download da JDK).

Para mais informações: http://www.netbeans.org/community/releases/55/relnotes.html

Desenvolvimento de Aplicações Móveis 2

Page 3: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

Colaboradores que auxiliaram no processo de tradução e revisãoAécio JúniorAlexandre MoriAlexis da Rocha SilvaAllan Souza NunesAllan Wojcik da SilvaAnderson Moreira PaivaAndre Neves de AmorimAngelo de OliveiraAntonio Jose R. Alves RamosAurélio Soares NetoBruno da Silva BonfimCarlos Fernando GonçalvesDenis Mitsuo Nakasaki

Fábio BombonatoFabrício Ribeiro BrigagãoFrancisco das ChagasFrederico DubielHerivelto Gabriel dos SantosJacqueline Susann BarbosaJoão Vianney Barrozo CostaKefreen Ryenz Batista LacerdaKleberth Bezerra G. dos SantosLeandro Silva de MoraisLeonardo Ribas SegalaLucas Vinícius Bibiano ThoméLuciana Rocha de Oliveira

Luiz Fernandes de Oliveira Junior Marco Aurélio Martins BessaMaria Carolina Ferreira da SilvaMassimiliano GiroldiMauro Cardoso MortoniPaulo Afonso CorrêaPaulo Oliveira Sampaio ReisPedro Henrique Pereira de AndradeRonie DotzlawSeire ParejaSergio TerzellaVanessa dos Santos AlmeidaRobson Alves Macêdo

Auxiliadores especiais

Revisão Geral do texto para os seguintes Países:

• Brasil – Tiago Flach• Guiné Bissau – Alfredo Cá, Bunene Sisse e Buon Olossato Quebi – ONG Asas de Socorro

Coordenação do DFJUG

• Daniel deOliveira – JUGLeader responsável pelos acordos de parcerias• Luci Campos - Idealizadora do DFJUG responsável pelo apoio social• Fernando Anselmo - Coordenador responsável pelo processo de tradução e revisão,

disponibilização dos materiais e inserção de novos módulos• Rodrigo Nunes - Coordenador responsável pela parte multimídia• Sérgio Gomes Veloso - Coordenador responsável pelo ambiente JEDITM (Moodle)

Agradecimento Especial

John Paul Petines – Criador da Iniciativa JEDITM

Rommel Feria – Criador da Iniciativa JEDITM

Desenvolvimento de Aplicações Móveis 3

Page 4: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

1. Objetivos

Nesta lição, discutiremos as características dos dispositivos móveis e a forma de iniciar o desenvolvimento de aplicações para estes dispositivos. Realizaremos uma introdução à Java Platform, Micro Edition (Java ME) incluindo a importância das configurações e perfis.

Ao final desta lição, o estudante será capaz de:

• Identificar as características dos dispositivos móveis

• Descrever a arquitetura JME

• Conhecer a personalização das configurações e perfis (CLDC e CDC)

• Identificar as bibliotecas fornecidas pelo MIDP

• Descrever o ciclo de vida de um MIDlet

Desenvolvimento de Aplicações Móveis 4

Page 5: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

2. Dispositivos Móveis

Dispositivos móveis podem variar em tamanho, projeto e layout, mas eles possuem algumas características em comum que são totalmente diferentes de sistemas desktop.

• Pequenos em tamanho

Dispositivos móveis são pequenos em tamanho. Consumidores desejam dispositivos pequenos pela mobilidade e conveniência.

• Memória Limitada

Dispositivos móveis também possuem pouca memória, tanto primária (RAM) quanto secundária (disco). Esta limitação é um dos fatores que afetam a escrita de classes para estes tipos de dispositivos. Com quantidade limitada de memória, devemos fazer considerações especiais acerca da conservação no uso de recursos preciosos.

• Poder de processamento limitado

Sistemas móveis não são poderosos como são os sistemas desktop quanto a sua organização. Tamanho, tecnologia e orçamento são alguns dos fatores que influenciam a condição desses recursos. Como o disco de armazenamento e RAM, apenas pequenos pacotes se adequam a estes recursos.

• Baixo consumo de energia

Dispositivos móveis possuem baixo consumo de energia em relação às máquinas desktop. Estes dispositivos necessitam poupar o uso de energia, pois possuem um limitado abastecimento através de baterias.

• Robusto e confiável

Por serem dispositivos móveis provavelmente serão carregados. Precisam ser robustos o suficiente para suportarem a força de impacto, movimento e ocasionalmente quedas.

• Conectividade limitada

Dispositivos móveis têm baixa largura de banda, alguns deles não suportam conexão. Outros destes usam conexões de rede sem fio.

• Curto tempo de inicialização

Estes dispositivos inicializam-se em segundos. Tomemos o caso de telefones móveis: eles se iniciam em segundos e as pessoas não ficam com estes desligados mesmo à noite. PDAs inicializam no segundo em que é pressionado o botão de ligar.

Desenvolvimento de Aplicações Móveis 5

Page 6: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

3. Visão sobre a Java ME

3.1. Plataforma Java

Java foi criado em 1991 por James Gosling, da Sun Microsystems. Inicialmente chamada de OAK, em homenagem a árvore que ficava do lado de fora vista da janela de Gosling, este nome foi modificado para Java porque já existia uma linguagem chamada OAK.

A motivação original para Java estava na necessidade para uma linguagem independente de plataforma que fosse embarcada em vários produtos eletrônicos de consumo como torradeiras e refrigeradores. Um dos primeiros projetos desenvolvidos usando Java foi um controle remoto pessoal chamado de Star 7.

Nessa mesma direção, e ao mesmo tempo, a World Wide Web e a Internet estavam ganhando popularidade. Gosling tornava Java capaz de ser usada para a programação para Internet.

Com o lançamento da versão 1.2, a plataforma Java foi classificada em várias plataformas: Java Standard Edition (Java SE), Java Enterprise Edition (Java EE), Java Micro Edition (Java ME) e Java Card API.

Java SE – Java Platform, Standard Edition aplicações desktop

Java EE – Java Platform, Enterprise Edition aplicações corporativas com ênfase no modelo de desenvolvimento server-side incluindo servlets, JSP, EJB e XML

Java ME – Java Platform, Micro Edition móveis e dispositivos de mão

JavaCard Cartões com chip

ServersServidores

Java Micro Edition (Java ME)

Máquinasdesktop

Dispositivosde alto consumo Dispositivos

de baixo consumo

Cartõescom chip

Java EEJava SE

CDC

Foundation Profile

Personal Profile

CLDC

MIDP

PacotesOpcionais

PacotesOpcionais

JavaCard

Máquina Virtual Java KVM Card VM

Figura 1: A plataforma Java

Desenvolvimento de Aplicações Móveis 6

Page 7: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

3.2 Visão Geral do JME

A Plataforma Java Micro Edition (Java ME) é um conjunto de especificações e tecnologias que têm o foco em dispositivos pessoais. Estes dispositivos têm uma quantidade limitada de memória, menor poder de processamento, pequenas telas e baixa velocidade de conexão.

Com a proliferação dos dispositivos pessoais, desde telefones, PDAs, videogames portáteis a aplicações domésticas, Java fornece um único ambiente portátil de desenvolvimento e execução destes dispositivos.

Classes JME, assim como todas as classes Java, são interpretadas. Elas são compiladas em byte codes e interpretadas por uma Máquina Virtual Java (JVM). Isto significa que estas classes não são afetadas pelas peculiaridades de cada dispositivo. O JME fornece uma interface consistente com os dispositivos. As aplicações não têm que ser recompiladas para poderem ser executadas em diferentes aparelhos.

No núcleo do JME estão uma configuração e perfis. Uma configuração define um ambiente de execução básico para um sistema JME. Isto define as características das bibliotecas principais, da máquina virtual, segurança e comunicação em rede.

Aplicações

Perfis PacotesOpcionais

OEMAPIs

Configuração {

Sistema Operacional do Dispositivo

BibliotecasMáquina Virtual Java

Figura 2: Arquitetura do JME

Um perfil adiciona uma biblioteca para certas classes de dispositivos. Os perfis fornecem bibliotecas da API de interface com o usuário, persistência e mensagens, entre outras.

Um conjunto ou pacote opcional de bibliotecas que fornecem classes funcionais adicionais. A inclusão destes pacotes no JME pode variar porque depende da capacidade do dispositivo. Por exemplo, alguns dispositivos MIDP não possuem Bluetooth, logo as APIs de Bluetooth não são incluídas nestes dispositivos.

3.3 Configuração

Uma configuração define características mínimas de um ambiente de execução Java completo. Para garantir ótima portabilidade e interoperabilidade entre vários tipos de requisitos de recursos de dispositivos (restrições de memória, processador e conexão), as configurações não contêm as mesmas características opcionais. Uma configuração JME define um complemento mínimo da tecnologia Java. Ela baseia-se nos perfis para definir bibliotecas adicionais (opções possíveis) para uma determinada categoria de dispositivo.

Uma configuração define:

– o subconjunto da linguagem de programação Java

– a funcionalidade da Máquina Virtual Java (JVM)

– bibliotecas do núcleo da plataforma

– características de segurança e comunicação em rede

Desenvolvimento de Aplicações Móveis 7

Page 8: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

3.4 Perfis

Um perfil define um conjunto adicional de bibliotecas e características de empresas, de categoria, de dispositivo ou de indústria. Enquanto uma configuração define uma base de bibliotecas, perfis definem as bibliotecas que são importantes para construir aplicações efetivas. Estas bibliotecas incluem a interface com o usuário, comunicação em rede e classes de armazenamento.

Desenvolvimento de Aplicações Móveis 8

Page 9: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

4. CLDC

A Configuração de Dispositivos de Conexão Limitada (Connected Limited Device Configuration – CLDC) define e endereça as seguintes áreas:

• Características da linguagem Java e Máquina Virtual (JVM)

• Bibliotecas de núcleo (java.lang.*, java.util.*)

• Input/Output (java.io.*)

• Segurança

• Comunicação em rede

• Internacionalização

4.1. Características Removidas

Algumas características do JSE que foram removidas do CLDC:

• finalização de instâncias de classes

• exceções assíncronas

• algumas classes de erros

• carregadores de classes definidas pelo usuário

• reflexão

• Java Native Interface (JNI)

• grupos de processos e processos daemon

Reflexão, Java Native Interface (JNI) e carregadores de classes definidas pelo usuário são potenciais falhas de segurança. JNI exigem muita memória e pode não ser suportada por dispositivos móveis de pouca memória.

4.2. Características dos Dispositivos CLDC

Os dispositivos atingidos pelo CLDC possuem estas características:

• no mínimo 192kb de memória para a plataforma Java (160kb de memória não-volátil para Máquina Virtual e bibliotecas e 32kb de memória volátil para execução da Máquina Virtual)

• processador de 16 ou 32 bits

• baixo consumo de energia (normalmente os que utilizam baterias)

• conexão limitada ou intermitente com velocidade também limitada (normalmente wireless)

A CLDC não define instalação da aplicação e ciclo de vida, interfaces com o usuário e tratamento de eventos. Está para os perfis abaixo da CLDC definir estas áreas. Em particular, a especificação MIDP é que define uma aplicação de MIDP (MIDlet) que possui um ciclo de vida, biblioteca Gráfica e controle de eventos (classes javax.microedition.lcdui.*).

4.3. Verificação de Classe

A especificação CLDC exige que todas as classes passem por um processo de verificação de duas fases. A primeira verificação (pré-verificação) deverá está terminada antes da instalação no dispositivo. A segunda verificação ocorre no dispositivo durante a execução, realizada pela Máquina Virtual Java (JVM).

Desenvolvimento de Aplicações Móveis 9

Page 10: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

compilar (javac)

pré-verificar

verificar(execução)

interpretar

File.java

File.class

File.class

Máquina de Desenvolvimento Dispositivo

Instalação

Figura 3: Processo de Verificação em duas fases

4.4. O Framework Genérico de Conexão (GCF)

O Framework Genérico de Conexão fornece as APIs básicas para conexão em CLDC. Este framework fornece uma base comum para conexões como HTTP, Sockets e Datagramas. O GCF fornece um conjunto genérico e comum de APIs que abstraem todos os tipos de conexão. Note-se que nem todos os tipos de conexões são exigidas para serem implementados em dispositivos MIDP.

A hierarquia de interface extensível do GCF torna a generalização possível. Novos tipos de conexões podem ser adicionados neste framework através de extensões desta hierarquia.

StreamConnectionNotifier

Connection

DatagramConnection

InputConnection OutputConnection

StreamConnection

ContentConnection

Figura 4: A Hierarquia de Conexão GCF

Desenvolvimento de Aplicações Móveis 10

Page 11: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

5. CDC

A Configuração de Dispositivo Conectada (CDC - Connected Device Configuration) é um super-conjunto da CLDC. Ela provê um ambiente de execução Java mais amplo que o da CLDC e é um ambiente mais próximo do da JSE.

Figura 5: Visão da CDC

A Máquina Virtual Java CDC (ou CVM) é uma Máquina Virtual Java completa. A CDC contém todas as APIs da CLDC. Ela provê um subconjunto maior das classes da JSE.

Como a CLDC, a CDC não define nenhuma classe de interface com o usuário. As bibliotecas de interface com o usuário são definidas pelos perfis desta configuração.

As classes incluídas na CDC vêm dos seguintes pacotes:

• java.io • java.lang • java.lang.ref • java.lang.math • java.net • java.security • java.security.cert • java.text • java.util • java.util.jar • java.util.zip

CDC também inclui o Framework de Conexão Genérica. Ela requer tipos de conexão adicionais como suporte para arquivo e datagrama.

Desenvolvimento de Aplicações Móveis 11

Page 12: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

6. JWTI

A Tecnologia Java Para a Indústria Sem Fio (JWTI - Java Technology for the Wireless Industry) especifica um conjunto de serviços e especificações padrão. De acordo com a especificação JWTI, seu principal objetivo é "minimizar a fragmentação de APIs no mercado de telefones celulares, e entregar uma especificação clara e previsível para os fabricantes de dispositivos, operadores e desenvolvedores de aplicação".

Por atenderem à JWTI, as aplicações rodarão em um conjunto maior de dispositivos. Os fabricantes de dispositivos irão se beneficiar também porque um conjunto maior de aplicações estará disponíveis para seus dispositivos.

MIDlets

MIDP 2.0 PacotesOpcionais

OEMAPIs

CLDC 1.0 or 1.1

WMA1.1

MMAPI1.1

Sistema Operacional do Dispositivo

Figura 6: Componentes JWTI

Desenvolvimento de Aplicações Móveis 12

Page 13: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

7. MIDP

O Perfil de Dispositivo de Informação Móvel (MIDP - Mobile Information Device Profile) é contruído sobre a CLDC. Não se deve escrever aplicações móveis úteis apenas usando as APIs CLDC. É na MIDP que as APIs de interface com o usuário são definidas.

A especificação MIDP, assim como a CLDC e outras APIs, foi definida através do Java Community Process (JCP). Foi envolvido um grupo de profissionais de mais de 50 empresas, composta de fabricantes de dispositivos móveis, operadoras e desenvolvedores de software. A MIDP está continuamente evoluindo, com futuras versões passando pelo mesmo rigor do processo do JCP. Versões futuras do MIDP terão compatibilidade com as versões anteriores, como no caso do MIDP1 e MIDP 2.0.

A especificação MIDP define que um dispositivo MID deve ter as seguintes características, no mínimo:

• Visor: • Tamanho da Tela: 96x54 • Profundidade do Visor: 1-bit • Pixel aspect ratio: aproximadamente 1:1

• Entrada: • Um ou mais dos seguintes mecanismos de entrada: teclado de uma mão, teclado de duas

mãos ou tela de toque

• Memória: • 256 kilobytes de memória não volátil para a implementação MIDP, mais o que for requerido

pela CLDC• 8 kilobytes de memória não volátil para os dados persistentes criados pela aplicação• 128 kilobytes de memória volátil para o ambiente Java (ex. Java heap)

• Rede: • Sem fio, duas vias, possivelmente intermitente, com largura de banda ilimitada

• Som: • A habilidade de tocar sons, via hardware dedicado ou via software

MIDP define o modelo de aplicação, a API de interface com o usuário, o armazenamento persistente e a rede, API de mídia e jogos, políticas de segurança, entrega da aplicação e provisionamento over-the-air.

Desenvolvimento de Aplicações Móveis 13

Page 14: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

8. MIDlet

Uma aplicação MIDP é chamada de MIDlet. O software de gerenciamento da aplicação (AMS - Application Management Software) do dispositivo interage diretamente com o MIDlet com os métodos de criar, iniciar, pausar e destruir o MIDlet.

O MIDlet é parte do pacote javax.microedition.midlet. Necessita estender a classe MIDlet. E pode requisitar parâmetros do AMS conforme definido no descritor da aplicação (JAD – Java Application Descriptor).

Um MIDlet não utiliza o método public static void main(String[] args). Caso possua, este não será reconhecido pelo AMS como o ponto de início do programa.

8.1. Ciclo de Vida do MIDlet

A vida de um MIDlet começa quando ele é instanciado pelo AMS. Ele inicialmente entra no estado pausado após ser criado com comando new. O AMS chama o construtor público sem argumento do MIDlet. Se uma exceção ocorrer no construtor, o MIDlet é colocado no estado destruído e é descartado imediatamente.

O MIDlet entra no estado ativo depois de se chamar o método startApp() pelo AMS.

O MIDlet entra no estado destruído quando o AMS chama o método destroyApp(). Este estado também é atingido quando o método notifyDestroyed() retorna com sucesso para a aplicação. Observe que o MIDlet entra no estado destruído somente uma vez no seu tempo de vida.

Ativo

Pausado

Destruído

destroyApp()

destroyApp()

startApp()

pauseApp()

new

Figura 7: Ciclo de Vida do MIDlet

8.2 MIDlet Suites

As aplicações de MIDP são empacotadas e entregues aos dispositivos como MIDlet suites. Um MIDlet suite consiste em um Arquivo Java (JAR) e, opcionalmente, um descritor de aplicação Java (JAD).

Um arquivo JAD é um arquivo texto contendo um conjunto de atributos, alguns dos quais são requeridos.

Desenvolvimento de Aplicações Móveis 14

Page 15: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

9. Exercícios

9.1. Quais são as vantagens do uso de Java como plataforma de desenvolvimento e execução para os dispositivos móveis?

• aplicações altamente portáteis• interfaces ricas, bem definidas para o dispositivo• espaço de memória baixa (KVM)• ambiente execução seguro• aplicações dinâmicas (podem carregar aplicações para um dispositivo)

9.2. O que o motivaria para escrever para programas para os dispositivos móveis?

• o desafio de escrever aplicações otimizadas

• novos conhecimentos

• fator diversão

Desenvolvimento de Aplicações Móveis 15

Page 16: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

Módulo 5Desenvolvimento de Aplicações Móveis

Lição 2Como Começar

Versão 1.0 - Set/2007

Page 17: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

1. Objetivos

Nesta lição, escreveremos e construiremos aplicações Java ME utilizando o emulador e empacotador de aplicações. A IDE que utilizaremos será o NetBeans 5.5 (www.netbeans.org) com o pacote adicional denominado NetBeans Mobility Pack 5.5 (pode ser obtido no mesmo site).

Uma IDE (Integrated Development Environment) é um ambiente de programação com um construtor de GUI, um editor de código ou texto, um compilador e/ou um interpretador e um depurador. No nosso caso, o NetBeans vem também com um emulador de dispositivos. Isto permite ver como o programa parecerá num dispositivo real.

Ao final desta lição, o estudante será capaz de:

• Entender a estrutura de um MIDlet

• Criar um projeto Mobile no NetBeans

• Criar e executar um MIDlet no NetBeans

Desenvolvimento de Aplicações Móveis 4

Page 18: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

2. "Hello, world!" MIDlet

Vimos na lição anterior o ciclo de vida de um MIDlet. A vida de um MIDlet inicia quando ele é criado pelo Application Management System (AMS) do dispositivo. Inicialmente, ele fica no estado "pausado".

Ativo

Pausado

Destruído

destroyApp()

destroyApp()

startApp()

pauseApp()

new

Figura 1: Ciclo de Vida do MIDlet

Para ser capaz de criar um MIDlet, devemos criar uma subclasse da classe MIDlet do pacote javax.microedition.midlet. Deve-se sobrescrever ou implementar os métodos: startApp(), destroyApp() e pauseApp(). Estes são os métodos esperados pelo AMS para se executar e controlar o MIDlet.

Diferentemente de um programa Java típico onde o método main() é executado automaticamente somente uma única vez na vida de um programa, o método startApp() pode ser chamado mais de uma vez durante o ciclo de vida do MIDlet. Então, não se deve colocar códigos de inicialização única no método startApp(). Para isso, deve ser criado um construtor para o MIDlet e as inicializações devem ser feitas nele.

Eis o código de nosso primeiro programa MIDP:

import javax.microedition.midlet.*;import javax.microedition.lcdui.*;public class HelloMidlet extends MIDlet implements CommandListener { Display display; Command exitCommand = new Command("Exit", Command.EXIT, 1); Alert helloAlert; public HelloMidlet(){ helloAlert = new Alert( "Hello MIDlet", "Hello, world!", null, AlertType.INFO ); helloAlert.setTimeout(Alert.FOREVER); helloAlert.addCommand(exitCommand); helloAlert.setCommandListener(this); } public void startApp() { if (display == null){ display = Display.getDisplay(this); } display.setCurrent(helloAlert);

Desenvolvimento de Aplicações Móveis 5

Page 19: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

} public void pauseApp() { } public void destroyApp(boolean unconditional) { } public void commandAction(Command c, Displayable d){ if (c == exitCommand){ destroyApp(true); notifyDestroyed(); // Exit } }}

A seguir, dissecaremos o primeiro MIDlet, focando em cada linha de código:

public class HelloMidlet extends MIDlet implements CommandListener {

Como dito anteriormente, é criada uma subclasse de MIDlet para criar nosso programa MIDP. Nessa linha, foi criada uma subclasse de MIDlet estendendo-a e dando o nome HelloMidlet. Além disso, implementaremos a interface CommandListener. Veremos sua função mais a frente.

Display display; Command exitCommand = new Command("Exit", Command.EXIT, 1); Alert helloAlert;

Estes são os atributos do MIDlet. O objeto Display (existe somente um display associado por MIDlet) será utilizado para desenhar na tela do aparelho. O objeto exitCommand é um comando que poderemos inserir na aplicação, por exemplo, para que possamos finalizar o programa. Se não fosse colocado qualquer comando de saída, não haveria forma de finalizar um MIDlet de forma normal. Este será montado da seguinte forma:

public HelloMidlet(){ helloAlert = new Alert( "Hello MIDlet", "Hello, world!", null, AlertType.INFO ); helloAlert.setTimeout(Alert.FOREVER); helloAlert.addCommand(exitCommand); helloAlert.setCommandListener(this); }

O construtor inicializa o objeto Alert. A classe Alert será discutida nas próximas lições. O método addCommand() do objeto Alert mostra um comando "Exit" na tela. O método setCommandListener() avisa o sistema para passar todos os eventos de comando para o MIDlet.

public class HelloMidlet extends MIDlet implements CommandListener {

O código "implements CommandListener" serve para controlar o pressionamento das teclas e comandos, de forma que o programa seja capaz de manipular eventos de "command". Se a classe implementar a interface CommandListener, deve ser criado o método commandAction(), como se segue:

public void commandAction(Command c, Displayable d){ if (c == exitCommand){ destroyApp(true); notifyDestroyed(); // Exit } }

Usamos o commandAction() somente para as requisições de saída. Finalizamos a nossa classe utilizando o método notifyDestroyed() se o comando “Exit” for enviado.

public void startApp() { if (display == null){ display = Display.getDisplay(this); } display.setCurrent(helloAlert);

Desenvolvimento de Aplicações Móveis 6

Page 20: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

}

Este é o ponto de entrada da nossa classe, uma vez que está pronta para ser iniciada pelo AMS. Lembre-se que o método startApp() pode ser incluído mais de uma vez no ciclo de vida do MIDlet. Se um MIDlet é pausado (paused), por exemplo, quando ocorre uma chamada telefônica, neste momento entramos em estado de pausa (pauseApp). Após a chamada o AMS pode retornar o nosso programa e executar novamente o método startApp(). O método estático setCurrent(), da classe Display, informa ao sistema que queremos que o objeto alerta seja mostrado na tela. Podemos iniciar o objeto da exibição chamando o método estático getDisplay() da mesma classe.

O Netbeans cria automaticamente um Java Application Descriptor (JAD) para o nosso projeto. E insere o arquivo JAD na pasta "dist" localizada na pasta do projeto. Este é um exemplo de arquivo JAD criado pelo Netbeans:

MIDlet-1: HelloMidlet, , HelloMidletMIDlet-Jar-Size: 1415MIDlet-Jar-URL: ProjectHello.jarMIDlet-Name: ProjectHelloMIDlet-Vendor: VendorMIDlet-Version: 1.0MicroEdition-Configuration: CLDC-1.1MicroEdition-Profile: MIDP-2.0

Agora estamos prontos para compilar e rodar o nosso primeiro MIDlet.

Desenvolvimento de Aplicações Móveis 7

Page 21: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

3. Utilizando Netbeans e o Mobility Pack

O pré-requisito para esta lição, é o Netbeans 5.5 e o Mobility Pack que devem ser instalados em seu computador. Ambos são arquivos executáveis bastando ao aluno seguir as telas guias para efetuar corretamente a instalação.

Passo 1: Iniciar criando um novo Projeto (Opção File | New Project...).

Figura 2: Menu File do NetBeans

Passo 2: Selecionar a Categoria "Mobile"

Figura 3: Janela New Project – Selecionando a categoria

Desenvolvimento de Aplicações Móveis 8

Page 22: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

Passo 3: Selecionar "Mobile Application" e pressionar o botão Next

Figura 4: Janela New Project – Selecionando o tipo de projeto

Passo 4:Nomear o projeto e especificar sua localização

Desmarcar a opção "Create Hello MIDlet", criaremos nosso MIDlet em próximas lições

Figura 5: Janela New Project – Selecionando o nome e localização do projeto

Desenvolvimento de Aplicações Móveis 9

Page 23: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

Passo 5: Selecionar a configuração do projeto (opcional)

Figura 6: Janela New Project – Selecionando a configuração do projeto

Etapa 6: Criar um novo MIDlet

Figura 7: Menu File do NetBeans

Desenvolvimento de Aplicações Móveis 10

Page 24: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

Etapa 7: Selecionar na opção Categories a opção MIDP e em File Types a opção MIDlet

Figura 8: Janela New File – Selecionando o tipo do arquivo

Etapa 8: Informar o nome do MIDlet (HelloMidlet) e pressionar o botão Finish

Figura 9: Janela New Project – Selecionando o nome e localização do projeto

Desenvolvimento de Aplicações Móveis 11

Page 25: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

Passo 9: Modificar o código do programa conforme descrito anteriormente

Figura 10: Janela New Project – Selecionando o nome e localização do projeto

Passo 10: Compilar e Executar o MIDlet de maneira idêntica à vista nos projetos anteriores

Figura 11: Janela New Project – Selecionando o nome e localização do projeto

Desenvolvimento de Aplicações Móveis 12

Page 26: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

Passo 11: Testar o MIDlet no Emulador

Figura 12: Janelas do Emulador da Aplicação

Desenvolvimento de Aplicações Móveis 13

Page 27: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

4. Exercícios

4.1. Múltiplos MIDlets em uma suite MIDlet

Adicionar um novo MIDlet ao projeto ProjectHello. Observar que o Netbeans adiciona automaticamente um novo MIDlet no arquivo de aplicações JAD quando é utilizado o auxílio "New File..."

Desenvolvimento de Aplicações Móveis 14

Page 28: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

Módulo 5Desenvolvimento de Aplicações Móveis

Lição 3Interface de Alto Nível para o Usuário

Versão 1.0 - Set/2007

Page 29: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

1. Objetivos

A interface de usuário MIDP foi desenhada para aparelhos portáteis. Aplicações MIDP são mostradas no limite de área da tela. Dispositivos de memória é o fator pelo qual os aparelhos portáteis possuem pouca memória.

Com os diferentes tipos de aparelhos móveis, dos mais variados modelos de telefones móveis aos PDAs, a interfase de usuário MIDP foi desenhada para ser flexível o bastante para ser utilizável em todos estes aparelhos.

Ao final desta lição, o estudante será capaz de:

• Conhecer as vantagens e desvantagens de se utilizar interfaces gráficas em alto e baixo nível

• Projetar MIDlets usando componentes de interface gráfica de alto nível• Identificar as diferentes subclasses de tela• Saber que diferentes itens podem ser utilizados na forma de objeto

Desenvolvimento de Aplicações Móveis 4

Page 30: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

2. Interface de usuário MIDP

MIDP possui classes que podem prover interfaces de usuário com altos e baixos níveis de funções. Interfaces gráficas de alto nível são desenhadas para serem flexíveis. A aparência desses componentes não está definida nas especificações. A aparência varia de aparelho para aparelho, mas o programador pode ficar seguro de que o comportamento de alto nível dos componentes será o mesmo em todas as especificações e implementações.

Interfaces Gráficas de Alto Nível Interfaces Gráficas de Baixo Nível

Altamente portátil entre aparelhos Pode ser específico do dispositivo

Aparência é a mesma nos aparelhos Aplicação com aparência específica

Navegação do tipo "rolagem" é encapsulada Tem que implementar suas próprias formas de navegação

Não podem definir a aparência real Definem a aparência em nível de pixel

Não são acessadas por aparelhos com características específicas

O acesso ao baixo nível de entrada é por intermédio do pressionamento de teclas

Figura 1: Comparação entre alto nível e baixo nível

2.1. Display

A principal parte da interface de usuário MIDP é a classe Display. Existe uma e apenas uma instância do Display para cada MIDlet. MIDlet pode pegar a referência do objeto Display utilizando o método estático getDisplay() da classe Display, e enviar a referência de um objeto do MIDlet.

MIDlet garante que o objeto Display não será modificado enquanto existir uma instância de MIDlet. Isso significa que o objeto retornado ao executamos o método getDisplay() é o mesmo não importando se essa chamada foi realizada nos métodos startApp() ou destroyApp() (veja mais sobre o ciclo de vida do Midlet).

2.2. Displayable

Apenas um componente Displayable pode ser mostrado de cada vez. Por padrão, Displayable não é mostrado no visor. Pode ser visível por intermédio da chamada do método setCurrent(). Este método pode ser chamado quando a aplicação se inicia, caso contrário, uma tela escura será mostrada ou a aplicação não se iniciará.

Ativo

Pausado

Destruído

destroyApp()

destroyApp()

startApp()

pauseApp()

new

Figura 2: Ciclo de Vida do MIDlet

Desenvolvimento de Aplicações Móveis 5

Page 31: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

O método startApp() da classe MIDlet é o local onde é possível inserir a chamada do método setCurrent(). Entretanto é necessário levar em consideração que o método startApp() pode ser chamado mais de uma vez durante a existência do MIDlet. Quando um MIDLet entra em pausa por intermédio do método pauseApp(), pode ser que tenha ocorrido uma chamada telefônica para atender. O método startApp() pode ser chamado novamente (após o finalização da chamada telefônica), assim como pela chamada do método setCurrent() dentro do método startApp(). Iremos obscurecer a tela que estava sendo mostrada antes do aplicativo entrar em pausa (ou seja, antes da chamada telefônica).

O componente Displayable pode ter um título, um conjunto de comandos, um commandListener e um Relógio.

Figura 3: Propriedades de Displayable

2.3. Title

O componente Displayable possui um título associado. A posição e aparência deste título é específica para cada tipo de aparelho e só pode ser determinada quando a aplicação estiver rodando. O título é associado ao Displayable por intermédio da chamada do método setTitle(). Chamando este método, o título do componente Displayable poderá mudar imediatamente. Se um Displayable está sendo apresentado na tela corrente, a especificação de estado do MIDP e o título devem ser alterados pela implementação “tão logo quanto seja permitido fazê-la”.

Passando um parâmetro nulo (null) para o método setTitle() remove-se o título do componente Displayable. Mudando ou removendo o título, pode-se afetar o tamanho da área disponível. Se a troca na área do visor ocorrer, o MIDlet pode ser modificada por intermédio do método sizeChanged().

2.4. Comando

Devido ao limite do tamanho da tela, MIDP não define uma barra de menu dedicada. No lugar da barra de menu MIDlets possuem comandos. Comandos são usualmente implementados pelo MIDP que podem ser chaves rápidas ou itens de menu. O objeto da classe Command contém informações somente sobre as ações que foram capturadas quando ativado, e não códigos que serão executados quando for selecionado.

A propriedade commandListener do componente Displayable contém as ações que serão executadas na ativação dos comandos. A commandListener é a interface que especifica um método simples:

public void commandAction(Command comando, Displayable mostravel)O mapeamento dos comandos no aparelho depende do número de botões rápidos ou botões programáveis disponíveis no aparelho. Se o número de comandos não se ajustar ao número de botões rápidos (softbuttons), o aparelho pode colocar alguns ou todos os comandos dentro do menu e mapear este menu para os botões rápidos com o título.

Desenvolvimento de Aplicações Móveis 6

Page 32: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

Command exitCommand = new Command("Exit", Command.EXIT, 1);Command newCommand = new Command("New Item", Command.OK, 1);Command renameCommand = new Command("Rename Item", Command.OK, 1);Command deleteCommand = new Command("Delete Item", Command.OK, 1);...list.addCommand(exitCommand);list.addCommand(newCommand);list.addCommand(renameCommand);list.addCommand(deleteCommand);

Figura 4: Amostra de mapeamento para múltiplos comandos

Um Command possui um label curto, um label longo e opcional, um tipo e uma prioridade.

2.4.1. Label

O tamanho reduzido da tela dos dispositivos é sempre um fator relevante quando se desenvolvem aplicações MIDP. Para os labels de comando, essa suposição também é aplicável. Os labels devem ser curtos, porém descritivos, para tanto devem caber na tela e serem compreensíveis para o usuário final.

Quando um label longo for especificado, deverá ser apresentado toda vez que o sistema considerar apropriado. Não existe uma chamada de API que especifique qual label deverá ser mostrado. É perfeitamente possível que alguns comandos apresentem um label curto enquanto que outros apresentem um longo.

2.4.2. Tipo de Comando

A maneira pela qual um comando é apresentado depende do dispositivo utilizado. Um programador pode especificar o tipo para este comando. Este tipo servirá como um auxílio para saber onde o comando deverá ser colocado. Não existe nenhuma forma de definir perfeitamente onde o comando deve ser apresentado na tela.

Os diferentes tipos de comandos são:

Command.OK, Command.BACK,Command.CANCEL, Command.EXIT,Command.HELP, Command.ITEM, Command.SCREEN, Command.STOP

Desenvolvimento de Aplicações Móveis 7

Page 33: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

Figura 5: A apresentação dos comandos é diferente em cada aparelho.

2.4.3. Prioridade de Comandos

A aplicação pode especificar a importância dos comandos na propriedade priority (prioridade). Esta é uma propriedade com um argumento do tipo Integer e quanto menor o número, maior a prioridade. Esta propriedade é também uma dica para ajudar a saber como o comando deverá ser posicionado. Casualmente a implementação determina a posição dos comandos pelo seu tipo. Se existir mais de um comando do mesmo tipo, a prioridade é normalmente considerada no posicionamento dos comandos.

2.5. CommandListener

O CommandListener é uma interface que possui um único método:

void commandAction(Command command, Displayable displayable)

O método commandAction() é chamado quando um comando é selecionado. A variável do comando é uma referência para o comando que foi selecionado. Displayable é onde o comando está localizado e onde a ação selecionada acontece.

O método commandAction deverá retornar imediatamente, caso contrário a execução da aplicação poderá ser bloqueada. Isto se deve pelo fato das especificações do MIDP não requisitarem implementações para a criar uma tarefa separada para cada evento entregue.

2.6. Ticker

O Ticker é uma contínua linha de rolagem de texto que acompanha a tela. O método construtor do Ticker aceita uma String para ser exibida. Ele só possui dois outros métodos, o padrão get e set para este texto: String getString() e void setString(String texto). Não existe possibilidade da aplicação controlar a velocidade e a direção do texto. A rolagem não pode ser pausada ou interrompida.

Se uma quebra de linha for embutida no texto, está não será apresentada na tela. Todas as linhas de texto deverão ser exibidas como uma única linha de texto rolante.

Um objeto Ticker é anexado a um dispositivo de exibição chamando-se o método setTicker(). Caso já exista um objeto Ticker anexado ao dispositivo, este será substituído pelo novo objeto passado como parâmetro.

Passando-se um parâmetro null para o método setTicker() ocorre a remoção qualquer objeto Ticker anexado do dispositivo. A remoção de um objeto Ticker do dispositivo pode afetar o tamanho de área válido para o conteúdo a ser exibido. Se uma mudança no tamanho da área de

Desenvolvimento de Aplicações Móveis 8

Page 34: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

exibição ocorrer, o MIDlet deverá ser notificado pelo método sizeChanged().

Os objetos Displayable podem compartilhar uma instância do objeto Ticker.

2.7. Screen

A classe Screen é a principal classe abstrata utilizada para aplicações gráficas de alto nível enquanto que a classe Canvas é a principal classe abstrata para aplicações gráficas de baixo nível.

Existem quatro subclasses da classe abstrata Screen: Form, TextBox, List e Alert.

Figura 6: Hierarquia de classes

2.8. Item

Componentes do tipo Item podem ser colocados em um componente do tipo container, como um Form ou um Alert. Um item pode possuir as seguintes propriedades:

Propriedade Valor Padrão

Label Especificado no construtor da subclasse

Commands nenhum

defaultCommand nulo

ItemCommandListener nulo

Layout directive LAYOUT_DEFAULT

Preferências de altura e largura -1 (destravado)

Figura 7: Hierarquia de Classe Item

Desenvolvimento de Aplicações Móveis 9

Page 35: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

A diretiva Layout especifica o formato de um item dentro de um objeto do tipo Form. A diretiva Layout pode ser combinada usando o operador de comparação binária OR (|). Todavia, diretivas de mesma orientação são mutuamente exclusiva.

Estas são as diretivas de alinhamento horizontal mutuamente exclusivas:

LAYOUT_LEFTLAYOUT_RIGHTLAYOUT_CENTER

Estas são as diretivas de alinhamento vertical mutuamente exclusivas:

LAYOUT_TOP LAYOUT_BOTTOM LAYOUT_VCENTER

Outras diretivas de layout não mutuamente exclusiva são:

LAYOUT_NEWLINE_BEFORE LAYOUT_NEWLINE_AFTER LAYOUT_SHRINK LAYOUT_VSHRINK LAYOUT_EXPAND LAYOUT_VEXPAND LAYOUT_2

Desenvolvimento de Aplicações Móveis 10

Page 36: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

3. Alert

A classe Alert gera uma tela na qual é possível exibir um texto e uma imagem. É um componente para exibir erro, aviso, texto e imagem informativa ou trazer uma tela de confirmação para o usuário.

É exibido por um determinado período de tempo. Este tempo pode ser fixado utilizando-se o método setTimeout() e especificado em milissegundos. Pode ser construído para ser exibido até que o usuário ative um comando Done dentro do intervalo de tempo de espera especificado pela contstante Alert.FOREVER.

O Alert pode também exibir um componente do tipo Gauge como um indicador. Quando um Alert conter um texto esse não ajustará a tela inteira e deverá ser rolado. Alert é fixado automaticamente para modal (tempo de espera fixado para Alert.FOREVER).

import javax.microedition.midlet.*;import javax.microedition.lcdui.*;public class AlertMidlet extends MIDlet implements CommandListener { Display display; Form mainForm; Command exitCommand = new Command("Exit", Command.EXIT, 0); Command okCommand = new Command("Ok", Command.OK, 0); Gauge gauge = new Gauge(null, false, 5, 0); Command[] commands = { new Command("Alarm", Command.OK, 0), new Command("Confirmation", Command.OK, 0), new Command("Info", Command.OK, 0), new Command("Warning", Command.OK, 0), new Command("Error", Command.OK, 0), new Command("Modal", Command.OK, 0) }; Alert[] alerts = { new Alert("Alarm Alert", "Example of an Alarm type of Alert", null, AlertType.ALARM), new Alert("Confirmation Alert", "Example of an CONFIRMATION type of Alert", null, AlertType.CONFIRMATION), new Alert("Info Alert", "Example of an INFO type of Alert", null, AlertType.INFO), new Alert("Warning Alert", "Example of an WARNING type of Alert, w/ gauge indicator", null, AlertType.WARNING), new Alert("Error Alert", "Example of an ERROR type of Alert, w/ an 'OK' Command", null, AlertType.ERROR), new Alert("Modal Alert", "Example of an modal Alert: timeout = FOREVER", null, AlertType.ERROR), }; public AlertMidlet(){ mainForm = new Form("JEDI: Alert Example"); mainForm.addCommand(exitCommand); for (int i=0; i< commands.length; i++){ mainForm.addCommand(commands[i]); } mainForm.setCommandListener(this); // Adiciona um objeto Gauge e envia o tempo limite alerts[3].setIndicator(gauge); alerts[3].setTimeout(5000); // Adiciona um comando para este Alert

Desenvolvimento de Aplicações Móveis 11

Page 37: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

alerts[4].addCommand(okCommand); // Define o Alert como Modal alerts[5].setTimeout(Alert.FOREVER); } public void startApp() { if (display == null){ display = Display.getDisplay(this); display.setCurrent(mainForm); } } public void pauseApp() {} public void destroyApp(boolean unconditional) {} public void commandAction(Command c, Displayable d){ if (c == exitCommand){ destroyApp(true); notifyDestroyed(); // Exit } for (int i=0; i<commands.length; i++){ if (c == commands[i]){ display.setCurrent(alerts[i]); } } }}

INFO Alert Alert Modal Alert com o indicador gauge

Figura 8: Diferentes tipos de Alert

Desenvolvimento de Aplicações Móveis 12

Page 38: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

4. List

A classe List é uma subclasse de Screen e fornece uma lista de escolhas. Este objeto pode assumir três modelos: IMPLICIT, EXCLUSIVE ou MULTIPLE.

List é IMPLICIT e o usuário executar o botão "select", o método commandAction() da classe List será chamada. O comando padrão é List.SELECT_COMMAND. O comando commandListener pode ser chamado através do comando padrão List.SELECT_COMMAND.

O método getSelectedIndex() retorna o índice do elemento atualmente selecionado para os tipos IMPLICIT e EXCLUSIVE. Para o tipo MULTIPLE, o método getSelectedFlags() retorna um atributo do tipo boolean contendo o estado dos elementos. O método isSelected(int index) retorna o estado do elemento na posição de índice dada.

import javax.microedition.midlet.*;import javax.microedition.lcdui.*;public class ListMidlet extends MIDlet implements CommandListener { Display display; List list; Command exitCommand = new Command("Exit", Command.EXIT, 1); Command newCommand = new Command("New Item", Command.OK, 1); Command renameCommand = new Command("Rename Item", Command.OK, 1); Command deleteCommand = new Command("Delete Item", Command.OK, 1); Ticker ticker = new Ticker(

"JEDI - Java Education and Development Initiative"); public ListMidlet(){ list = new List("JEDI: List Example", List.IMPLICIT); list.append("List Item #1", null); list.append("List Item #2", null); list.append("List Item #3", null); list.setTicker(ticker); list.addCommand(exitCommand); list.addCommand(newCommand); list.addCommand(renameCommand); list.addCommand(deleteCommand); list.setCommandListener(this); } public void startApp() { if (display == null){ display = Display.getDisplay(this); display.setCurrent(list); } } public void pauseApp() { } public void destroyApp(boolean unconditional) { } public void commandAction(Command c, Displayable d){ if (c == exitCommand){ destroyApp(true); notifyDestroyed(); // Exit } if (c == List.SELECT_COMMAND){ int index = list.getSelectedIndex(); String currentItem = list.getString(index); // realiza algo } }}

Desenvolvimento de Aplicações Móveis 13

Page 39: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

Lista IMPLICIT Lista EXCLUSIVE Lista MULTIPLEFigura 9: Tipos de lista

Desenvolvimento de Aplicações Móveis 14

Page 40: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

5. TextBox

A classe TextBox é a subclasse de Screen que pode ser usada para se obter a entrada de texto do usuário. Permite que o usuário incorpore e edite o texto. É similar à classe TextField (ver o item sobre TextField) pois permite a entrada de constraints e de modalidades. Sua diferença em relação a classe TextField é que o usuário pode inserir uma nova linha (quando a constraint da entrada é informada).

O texto digitado no objeto TextBox pode ser recuperado utilizando o método getString().

Figura 10: TextBox com múltiplas linhas

Figura 11: TextBox com o PASSWORD modificado

Desenvolvimento de Aplicações Móveis 15

Page 41: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

6. Form

A classe Form é uma subclasse da Screen. É um contêiner para itens das subclasses, tais como os objetos das classes TextField, StringItem, ImageItem, DateField e ChoiceGroup. Controla a disposição dos componentes e a transversal entre os componentes e o desdobramento da tela.

Itens são adicionados e inseridos a um objeto do tipo Form usando os métodos append() e insert(), respectivamente. Itens são eliminados usando o método delete(). Itens podem ser substituídos usando o método set(). Itens são referenciados usando o índice de base zero.

import javax.microedition.midlet.*;import javax.microedition.lcdui.*;public class MidletPrinc extends MIDlet implements CommandListener { private Command exitCmd = new Command("Exit", Command.EXIT, 0); private ScreenForm form; private Display display; public void startApp() { if (display == null) { form = new ScreenForm("Test Form"); display = Display.getDisplay(this); } display.setCurrent(form); } public void commandAction(Command command, Displayable displayable) { if (command == exitCmd) { try { destroyApp(true); } catch (MIDletStateChangeException ex) { ex.printStackTrace(); } notifyDestroyed(); } } protected void pauseApp() { } protected void destroyApp(boolean b) throws MIDletStateChangeException { } class ScreenForm extends Form { public ScreenForm(String title) { super(title); addCommand(exitCmd); setCommandListener(MidletPrinc.this); // Instruções para o Form } }}

Neste MIDlet observe o comentário “Instruções para o Form”. Este servirá como ponto de entrada para os próximos exemplos, que deverão serem inseridos exatamente a partir deste ponto.

Desenvolvimento de Aplicações Móveis 16

Page 42: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

7. ChoiceGroup

Um componente ChoiceGroup representa grupos de escolhas selecionadas. A escolha pode conter um texto, uma imagem ou ambas.

As escolhas podem ser EXCLUSIVE (somente uma opção pode ser selecionada) ou MULTIPLE (várias opções podem ser selecionadas de uma vez). Caso um objeto do tipo ChoiceGroup seja um tipo de POPUP, somente uma opção poderá ser selecionada. Uma seleção de popup será exibida quando este item for selecionado. Cabe ao usuário efetuar uma única escolha. A opção exibida é sempre a seleção escolhida.

O método getSelectedIndex() retorna o índice do elemento selecionado de um ChoiceGroup. O método getSelectedFlags() retorna um grupo de atributos do tipo boolean que corresponde ao estado de cada um dos elementos. O método isSelected(int index) retorna o estado de um elemento a partir da posição informada no atributo index.

// Insira estas instruções no FormChoiceGroup choiceExclusive = new ChoiceGroup("Exclusive", Choice.EXCLUSIVE);choiceExclusive.append("Male", null);choiceExclusive.append("Female", null);append(choiceExclusive); ChoiceGroup choiceMultiple = new ChoiceGroup("Multiple", Choice.MULTIPLE);choiceMultiple.append("Apple", null);choiceMultiple.append("Orange", null);choiceMultiple.append("Grapes", null);append(choiceMultiple); ChoiceGroup choicePopup = new ChoiceGroup("Popup", Choice.POPUP);choicePopup.append("Asia", null);choicePopup.append("Europe", null);choicePopup.append("Americas", null);append(choicePopup);

Figura 12: Modelos de Grupos de Escolha

Desenvolvimento de Aplicações Móveis 17

Page 43: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

8. DateField

O componente DateField é utilizado para as entradas de data e hora. Pode conter uma entrada de data (modo DATE), uma entrada de hora (modo TIME) ou ambas (modo DATE_TIME).

O método getDate() retorna o valor atual de um item e retornará null caso este item não seja inicializado. Caso o modo do DataField seja DATE, a hora do componente irá retornar zero. Se o modo for TIME, a data do componente é definido para "Janeiro 1, 1970".

// Insira estas instruções no FormDateField dateonly = new DateField("Birthday (DATE)", DateField.DATE);DateField timeonly = new DateField("Set Alarm (TIME)", DateField.TIME);DateField datetime = new DateField("Departure (DATE_TIME)", DateField.DATE_TIME); append(dateonly);append(timeonly);append(datetime);

Entrada de DateField Selecionando Datas Selecionando Horas

Figura 13: Modelos de DateField e telas de entrada

Desenvolvimento de Aplicações Móveis 18

Page 44: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

9. StringItem

Um componente StringItem é um componente somente de leitura. Sendo composto de um label e um texto.

Um objeto do tipo StringItem, opcionalmente, permite um argumento que representa a aparência. O modo de aparência pode ser definido através das constantes Item.PLAIN, Item.HYPERLINK ou Item.BUTTON.

Caso o modo da aparência seja do tipo HYPERLINK ou BUTTON, o comando padrão e o ItemCommandListener precisam ser definidos no item.

// Insira estas instruções no FormStringItem plain = new StringItem("Plain", "Plain Text", Item.PLAIN);StringItem hyperlink = new StringItem("Hyperlink", "http://www.sun.com", Item.HYPERLINK);hyperlink.setDefaultCommand(new Command("Set", Command.ITEM, 0));StringItem button = new StringItem("Button", "Click me", Item.BUTTON);button.setDefaultCommand(new Command("Set", Command.ITEM, 0));append(plain);append(hyperlink);append(button);

Figura 14: StringItem

Desenvolvimento de Aplicações Móveis 19

Page 45: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

10. ImageItem

O componente ImageItem é uma imagem gráfica que pode ser colocada em um componente, tal como um Form. O objeto ImageItem permite um objeto do tipo layout como parâmetro (veja mais na seção sobre Item):

public ImageItem( String label, Image img, int layout, String altText)

Outro construtor aceita uma modalidade de aparência, podendo ser um dos seguintes atributos definidos: Item.PLAIN, Item.HYPERLINK ou Item.BUTTON (ver mais na seção sobre StringItem):

public ImageItem(String label, Image image, int layout, String altText, int appearanceMode)

O arquivo "jedi.png" é importado para o projeto usando-se a operação de gerenciamento de arquivos do sistema e inserido no diretório do projeto sobre o subdiretório "src". O projeto é atualizado pelo clique com botão direito do mouse sobre o nome do projeto e seleção de "Refresh Folders".

// Insira estas instruções no Formtry { Image img = Image.createImage("/jedi.png"); ImageItem image = new ImageItem("JEDI", img, Item.LAYOUT_CENTER, "JEDI Logo"); append(image);} catch (Exception e){ e.printStackTrace();}

Figura 15: ImageItem

Desenvolvimento de Aplicações Móveis 20

Page 46: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

11. TextField

Um componente TextField é um item onde o usuário pode codificar a entrada. Diversas regras de entrada, mutuamente exclusivas, podem ser ajustadas:

TextField.ANY TextField.EMAILADDRTextField.NUMERIC TextField.PHONENUMBERTextField.URL TextField.DECIMAL

A entrada pode também ter estes modificadores:

TextField.PASSWORD TextField.UNEDITABLETextField.SENSITIVE TextField.NON_PREDICTIVETextField.INITIAL_CAPS_WORD TextField.INITIAL_CAPS_SENTENCE

Estes modificadores podem ser atribuídos usando-se o operador de comparação binária OR (|) (ou pelo uso do operador de comparação binária: XOR ^) sobre as regras de entrada. Consequentemente, modificadores podem ser derivados do valor do retorno do método getConstraints() ao operador de comparação binária AND (&).

Já que os modificadores são retornados pelo método getConstraints(), a entrada principal pode ser extraída pelo uso do operador de comparação binária com TextBox.CONSTAINT_MASK e o retorno do valor do método getConstaints().

O método getString() retorna o conteúdo do TextField como um valor do tipo caractere.

// Insira estas instruções no FormTextField ANY = new TextField("ANY", "", 64, TextField.ANY);TextField EMAILADDR = new TextField("EMAILADDR", "", 64, TextField.EMAILADDR);TextField NUMERIC = new TextField("NUMERIC", "", 64, TextField.NUMERIC);TextField PHONENUMBER = new TextField("PHONENUMBER", "", 64, TextField.PHONENUMBER);TextField URL = new TextField("URL", "", 64, TextField.URL);TextField DECIMAL = new TextField("DECIMAL", "", 64, TextField.DECIMAL); append(ANY);append(EMAILADDR);append(NUMERIC);append(PHONENUMBER);append(URL);append(DECIMAL);

Figura 16: TextField Items

Desenvolvimento de Aplicações Móveis 21

Page 47: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

12. Exercícios

12.1. Lista dinâmica

Criar um MIDlet com uma List do tipo IMPLICIT na tela principal. Anexar três comandos para esta List – "Add Item", "Remove Item" e "Exit". O comando "Add Item" alertará o usuário para uma entrada a lista usando um TextBox, então adicionará este antes do item selecionado na lista. "Remove Item" removerá o item selecionado da lista (dica, veja o método getSelectedIndex). O Comando "Exit" finalizará o Midlet.

Desenvolvimento de Aplicações Móveis 22

Page 48: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

Módulo 5Desenvolvimento de Aplicações Móveis

Lição 4Interface de Baixo Nível para o Usuário

Versão 1.0 - Set/2007

Page 49: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

1. Objetivos

Nas lições anteriores dissertamos sobre como construir interfaces do usuário tais como listas, formulários e dados de entrada. Aquelas eram interfaces de alto nível e o programador não tinha que se preocupar sobre como desenhar a tela ou posicionar o texto na tela. Todo programa tem que especificar apenas o tipo de componentes e o nomes dos elementos. O sistema encarrega-se de manusear o desenho, a rolagem e o layout da tela.

Uma desvantagem de se utilizar somente componentes de alto nível é que o programa não tem controle total sobre a tela. Há ocasiões em que queremos desenhar linhas, animar imagens e ter controle sobre cada ponto da tela.

Nesta lição trabalharemos diretamente com o desenho da tela. Estudaremos a classe Canvas, que deve ser o fundo de nosso desenho. Trabalharemos também com a classe Graphics que tem métodos para desenho de linhas, retângulos, arcos e texto. Também falaremos sobre fontes, cores e imagens.

Ao final desta lição, o estudante será capaz de:

• Compreender os eventos de baixo nível manuseados em MIDP• Desenhar e exibir texto, imagens, linhas, retângulos e arcos• Especificar cor, fonte e movimento para operações de desenho• Compreender e utilizar as classes Canvas e Graphics

Desenvolvimento de Aplicações Móveis 4

Page 50: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

2. Canvas

A classe Canvas é uma subclasse de Displayable. Uma classe abstrata que deve ser instanciada antes que uma aplicação possa fazer uso de suas funcionalidades.

Figura 1: Hierarquia de classes.

Pode ser implementada com a subclasse Screen de exibição. O programa pode alternar para Canvas e Screen. Define métodos vazios de manuseio. As aplicações devem implementá-los para manusear os eventos.

A classe define um método abstrato chamado paint(). Aplicações que utilizam esta classe devem providenciar a implementação deste método.

2.1. O sistema de Coordenadas

O sistema de coordenadas da classe Canvas é baseado no ponto de coordenada zero, ou seja, as coordenadas x e y iniciam com o valor zero. O canto esquerdo superior é a coordenada (0,0). A coordenada x é incrementada da esquerda para a direita, enquanto a coordenada y é incrementada de cima para baixo. Os métodos getWidth() e getHeight() retornam a largura e a altura do Canvas, respectivamente.

O canto inferior direito da tela tem as coordenadas nas posições getWidht()-1 e getHeight()-1. Quaisquer alterações no tamanho de desenho do Canvas é registrado para a aplicação pelo método sizeChange(). O tamanho disponível do Canvas pode mudar se acontecer uma troca entre os modos normal e tela cheia ou a adição ou remoção de componentes tais como Comandos.

Figura 2: O sistema Coordinate

2.2. "Hello, world!"

import javax.microedition.midlet.*;

Desenvolvimento de Aplicações Móveis 5

(0,0)increasing x value

incre

asin

g y v

alu

e

(getwidth()-1,getHeight()-1)

Page 51: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

import javax.microedition.lcdui.*;public class HelloCanvasMIDlet extends MIDlet { private Display display;

HelloCanvas canvas; Command exitCommand = new Command("Exit", Command.EXIT, 0); public void startApp() { if (display == null){ canvas = new HelloCanvas(this, "Hello, world!"); display = Display.getDisplay(this); } display.setCurrent(canvas); } public void pauseApp() { } public void destroyApp(boolean unconditional) { } protected void Quit(){ destroyApp(true); notifyDestroyed(); }}class HelloCanvas extends Canvas implements CommandListener { private Command exitCommand = new Command("Exit", Command.EXIT, 0); private HelloCanvasMIDlet midlet; private String text; public HelloCanvas(HelloCanvasMIDlet midlet, String text) { this.midlet = midlet; this.text = text; addCommand(exitCommand); setCommandListener(this); } protected void paint(Graphics g) { // Limpa a janela g.setColor(255, 255, 255 ); g.fillRect(0, 0, getWidth(), getHeight()); // Define a cor como preta g.setColor(0, 0, 0); // E escreve o texto g.drawString(text, getWidth()/2, getHeight()/2, Graphics.TOP | Graphics.HCENTER); }

public void commandAction(Command c, Displayable d) { if (c == exitCommand){ midlet.Quit(); } }}

Desenvolvimento de Aplicações Móveis 6

Page 52: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

Figura 3: Hello Word utilizando Canvas

Com o midlet “Hello, world!” definimos a classe que estende a classe Canvas

class HelloCanvas extends Canvas implements CommandListener {

Adicionamos um comando “Exit” (saída) e o colocamos como listener do comando

addCommand(exitCommand); setCommandListener(this);

Criamos um comando de listener através da implementação de uma classe CommandListener. Isto significa criar uma classe que tenha um método commandAction.

class HelloCanvas extends Canvas implements CommandListener { public void commandAction(Command c, Displayable d) { ... } }

O ponto central deste programa é o método paint(). A primeira chamada deste método limpa a tela:

g.setColor(255, 255, 255 ); g.fillRect(0, 0, getWidth(), getHeight());

E os métodos gráficos de baixo nível desenham a mensagem “Hello, world!” na tela:

g.setColor(0, 0, 0); g.drawString(text, getWidth()/2, getHeight()/2, Graphics.TOP | Graphics.HCENTER);

2.3. Comandos

Assim como as classes List, TextBox e Form, a classe Canvas pode possuir Commands anexados e pode escutar por eventos de comando. Os passos para adicionar um comando a um Canvas são os mesmos:

1. Criar um objeto da classe Command

private Command exitCommand = new Command("Exit", Command.EXIT, 0);

2. Utilizar o método addCommand() para anexar o comando ao objeto da classe Canvas (Form, List ou TextBox)

addCommand(exitCommand);

3. Utilizar o método setCommandListener() para registrar qual classe obtém os eventos de comando neste Displayable

Desenvolvimento de Aplicações Móveis 7

Page 53: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

setCommandListener(this);

4. Criar um commandListener para implementar a classe CommandListener e providenciar o método commandAction()

class HelloCanvas extends Canvas implements CommandListener { ... public void commandAction(Command c, Displayable d) { if (c == exitCommand){ // do something } }}

2.4. Eventos de Teclado

A classe Canvas pode ter uma interface listener para eventos de teclado que podem implementar os seguintes métodos:

keyPressed(int keyCode) Quando uma tecla é pressionadakeyRepeated(int keyCode) Quando uma tecla é repetida (quando é mantida pressionada)keyReleased(int keyCode) Quando uma tecla é liberada

A classe Canvas define os seguintes códigos de teclado: KEY_NUM0, KEY_NUM1, KEY_NUM2, KEY_NUM3, KEY_NUM4, KEY_NUM5, KEY_NUM6, KEY_NUM7, KEY_NUM8, KEY_NUM9, KEY_STAR, e KEY_POUND.

Para recuperar o nome da tecla deve-se utilizar o método getKeyName(int keyCode).

2.5. Ações de Jogo

Cada código de tecla pode ser mapeada para uma ação de jogo. A classe Canvas define estas ações: UP, DOWN, LEFT, RIGHT, FIRE, GAME_A, GAME_B, GAME_C, GAME_D. O programa pode traduzir um código de tecla em uma ação de jogo utilizando o método getGameAction(int keyCode).

O método getKeyCode(int gameAction) retorna o código de tecla associado com uma ação de jogo. Uma ação de jogo pode ter mais de um código de teclado associado. Se houver mais de um código de tecla associado com uma ação de jogo é retornado apenas um único código.

Uma aplicação deve utilizar o método getGameAction(int keyCode) ao invés de usar diretamente os códigos de teclado. Normalmente, se um programa precisa esperar por uma tecla “UP”, ele deveria utilizar o atributo KEY_NUM2 ou o código específico para o botão UP. No entanto, programas que utilizam este método não são portáveis em aparelhos que possam ter diferentes formatos para o código da tecla do botão UP. O KEY_NUM2 pode ser a “tecla UP” para um aparelho, entretanto, pode ser a “tecla LEFT” em outro aparelho. O método getGameAction() deve sempre retornar UP, independente de qual tecla foi pressionada já que é esta que está no contexto do aparelho.

2.6. Eventos de apontador

Apesar dos eventos de teclado, programas MIDP também podem conter eventos de apontador. Isto é verdade se o aparelho possuir um apontador e estiver implementado no sistema Java do aparelho

O método hasPointerEvents() retorna true se o aparelho suportar eventos de pressão e liberar um apontador. O método hasPointerMotionEvents() retorna true se o aparelho suportar eventos de movimentação de apontador.

public boolean hasPointerEvents()public boolean hasPointerMotionEvents()

Os eventos que são gerados por atividade de ponto são definidos pela implementação dos

Desenvolvimento de Aplicações Móveis 8

Page 54: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

métodos: pointerPressed, pointerReleased e pointerDragged. Uma aplicação precisa implementar estes métodos para ser notificada quando ocorrerem. As coordenadas x e y do evento (onde o apontador foi pressionado, solto ou arrastado) são especificadas como parâmetros nas assinaturas dos seguintes métodos:

protected void pointerPressed(int x, int y)protected void pointerReleased(int x, int y)protected void pointerDragged(int x, int y)

Desenvolvimento de Aplicações Móveis 9

Page 55: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

3. Gráficos

A classe Graphics é a principal classe para desenhar textos, imagens, linhas, retângulos e arcos. Possui métodos para especificar cor, fonte e estilo.

3.1. Cores

A classe Display possui métodos para determinar se o aparelho possui suporte a cor e o número de cores ou tons de cinza suportados por ele.

public boolean isColor() Retorna true se a tela suportar cor, retorna false se nãopublic int numColors() Retorna o número de cores (ou tons de cinza se o

aparelho não suportar cores) suportados pelo aparelho

Para definir a cor que será utilizada para os próximos métodos, utilize o método setColor(). Pode ser utilizado de duas maneiras:

public void setColor(int red, int green, int blue)public void setColor(int RGB)

Na primeira forma, especifica-se os componentes em padrão RGB, intensidade das cores vermelho (Red), verde (Green) e azul (Blue) que podem variar de 0 a 255. Na segunda forma, aos componentes da cor são especificados na forma de 0x00RRGGBB. As chamadas para inteiros no método setColor seguem o código da mesma maneira:

int red, green, blue;...setColor(red, green, blue);setColor( (red<<16) | (green<<8) | blue );

Outro métodos de manipulação de cores são:

public int getColor() retornar um inteiro da cor atual do formulário no formato 0x00RRGGBB

public int getRedComponent() retornar o valor da cor vermelho do componente atual public int getGreenComponent() retornar o valor da cor verde do componente atual public int getBlueComponent() retornar o valor da cor azul do componente atual public int getGrayScale() retornar o valor da escala de cinza da cor atual public void setGrayScale( int value)

definir o valor da escala de cinza para uma próxima instrução

3.2. Fontes

Um objeto do tipo Font possui três atributos: face, style e size. As fontes não são criadas pela aplicação. Ao invés disso, a aplicação pergunta ao sistema por determinados atributos da fonte e o sistema retorna uma fonte com estes atributos. O sistema não garante que irá retornar uma fonte com todos os atributos requeridos. Se o sistema não tem uma fonte igual a que requerida, retornará uma fonte próxima sem respeitar todos os atributos requeridos.

Font é uma classe separada. Como comentado anteriormente, a aplicação não cria um objeto padrão. Ao invés disso os métodos estáticos getFont() e getDefaultFont() são utilizados para obter uma fonte padrão para o sistema.

public static Font getFont( int face, int style, int size)

retornar um objeto do tipo Font do sistema com os atributos definidos

public static Font getDefaultFont() retornar a fonte padrão utilizada pelo sistemapublic static Font getFont(int fontSpecifier) retornar a fonte utilizada por um componente

gráfico de auto nível. O atributo fontSpecifier

Desenvolvimento de Aplicações Móveis 10

Page 56: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

pode ser:

FONT_INPUT_TEXT ou FONT_STATIC_TEXT

O formato da fonte é especificado pelo parâmetro face que pode assumir uma das seguintes constantes padrão: FACE_SYSTEM, FACE_MONOSPACE ou FACE_PROPORTIONAL.

O estilo da fonte é especificado pelo parâmetro style que pode assumir uma das seguintes constantes padrão: STYLE_PLAIN (padrão) ou a combinação de STYLE_BOLD (negrito), STYLE_ITALIC (itálico) e STYLE_UNDERLINED (sublinhado). Estilos podem ser combinados utilizando o operador OR (|). O estilo de uma fonte tipo negrito e itálico é declarado como:

STYLE_BOLD| STYLE_ITALIC

O tamanho da fonte é especificado pelo parâmetro size que pode assumir uma das seguintes constantes padrão: SIZE_SMALL, SIZE_MEDIUM ou SIZE_LARGE.

Estes métodos retornam os atributos específicos da fonte:

public int getStyle()public int getFace()public int getSize()public boolean isPlain()public boolean isBold()public boolean isItalic()public boolean isUnderlined()

3.3. Estilo do Traço

O método setStrokeStyle(int style) especifica o estilo do cursor que deverá ser usado para desenhar linhas, arcos e retângulos com cantos arredondados. O Estilo do cursor não afeta o texto, as imagens ou os preenchimentos.

public void setStrokeStyle( int style)

definir o estilo do cursor que deverá ser usado para desenhar linhas, arcos e retângulos com cantos arredondados

public int getStrokeStyle() retornar o estilo atual do cursor

Os valores válidos para o parâmetro style são uma das seguintes constantes padrão: SOLID ou DOTTED.

3.4. Clipping

Clipping é uma área retangular em um objeto gráfico. Qualquer operação gráfica deverá afetar apenas os pontos contidos na área de corte. Pontos fora da área de corte não serão afetados por qualquer operação gráfica.

public void setClip( int x, int y, int width, int height)

definir a área de corte para o retângulo especificado pelas coordenadas

public int getClipX() retornar o valor X da área de corte atual, relativo à origem deste contexto gráfico

public int getClipY() retornar o Y da área de corte atual, relativo à origem deste contexto gráfico

public int getClipWidth() retornar a largura da área de corte atualpublic int getClipHeight() retornar a altura da área de corte atual

3.5. Pontos Âncora

Textos são desenhados por um ponto inicial. O método drawString() espera as coordenadas localizada nos parâmetros x e y que são relativos aos pontos iniciais.

Desenvolvimento de Aplicações Móveis 11

Page 57: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

public void drawString(String str, int x, int y, int anchor)O ponto deve ser uma combinação da constante horizontal (LEFT, HCENTER ou RIGHT) e a constante vertical (TOP, BASELINE ou BOTTOM). As constantes horizontal e vertical devem ser combinadas utilizando o operador OU (|), por exemplo para desenhar o texto pela base horizontal do centro, será necessário um valor inicial de BASELINE | HCENTER.

TOP | LEFT

BOTTOM | HCENTER

BOTTOM | LEFT BOTTOM | RIGHT

TOP | RIGHT

TOP | HCENTER

BASELINE | LEFT BASELINE | RIGHT

BASELINE | HCENTER

Figura 4: Texto dos pontos iniciais

3.6. Desenhando Textos

Os métodos para desenhar texto e caracteres são:

public void drawString( String str, int x, int y, int anchor)

desenhar o texto definido pelo parâmetro str utilizando a cor e fonte atual. Os parâmetros x e y são as coordenadas do ponto inicial

public void drawSubstring( String str, int offset, int len, int x, int y, int anchor)

desenhar de maneira semelhante ao método drawString, exceto pelos parâmetros offset que limita a base-zero e len que é responsável pelo tamanho

public void drawChar( char character, int x, int y, int anchor)

desenhar o caractere usando a cor da fonte atual

public void drawChars( char[] data, int offset, int length, int x, int y, int anchor)

desenhar os caracteres contidos no parâmetro data, iniciando pelo índice definido no parâmetro offset com o tamanho especificado em length

Aqui estão alguns métodos da classe Font que são úteis para o desenho de texto:

public int getHeight() retornar a altura do texto desta fonte. O tamanho retornado inclui os espaçamentos extras. Isto assegura que o desenho de dois textos com esta distância a partir de um ponto de âncora para outro ponto de

Desenvolvimento de Aplicações Móveis 12

Page 58: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

âncora conterá espaço suficiente entre as duas linhas de texto

public int stringWidth(String str) retornar a largura total em pixels do espaço ocupado pelo parâmetro str se for escrito utilizando-se esta fonte

public int charWidth(char ch) retornar a largura total em pixels do espaço ocupado pelo parâmetro ch se for escrito utilizando-se esta fonte

public int getBaselinePosition() retornar a distância em pixels entre o TOPO e a BASE do texto, baseado nesta fonte

g.setColor(255, 0, 0); // vermelho g.drawString("JEDI",

getWidth()/2, getHeight()/2,Graphics.TOP | Graphics.HCENTER);

g.setColor(0, 0, 255); // azulFont font = g.getFont();g.drawString("Java Education & Development Initiative",

getWidth()/2, getHeight()/2+font.getHeight(),Graphics.TOP | Graphics.HCENTER);

Figura 5: Saída de operações de drawString()

3.7. Desenhando Linhas

O único método da classe Graphics utilizado para desenhar linhas é definido como:

public void drawLine(int x1, int y1, int x2, int y2)Este método desenha uma linha utilizando a cor e estilo corrente entre a coordenada inicial indicada nos parâmetros x1 e y1 e a coordenada final indicada nos parâmetros x2 e y2.

g.setColor(255, 0, 0); // vermelho// linha do canto superior esquerdo para o canto inferior direito da telag.drawLine(0, 0, getWidth()-1, getHeight()-1); g.setColor(0, 255, 0); // verde// linha horizontal no meio da telag.drawLine(0, getHeight()/2, getWidth()-1, getHeight()/2); g.setColor(0, 0, 255); // azul// linha horizontal na parte inferior da telag.drawLine(0, getHeight()-1, getWidth()-1, getHeight()-1); g.setColor(0, 0, 0); // preta

Desenvolvimento de Aplicações Móveis 13

Page 59: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

// linha do canto inferior esquerdo para o canto superior direito da telag.drawLine(0, getHeight()-1, getWidth()-1, 0);

Figura 6: Saída de chamadas a métodos de drawLine()

3.8. Desenhando Retângulos

Os métodos da classe Graphics para desenhar retângulos são:

public void drawRect(int x, int y, int width, int height)public void drawRoundRect(int x, int y,

int width, int height,int arcWidth, int arcHeight)

public void fillRect(int x, int y, int width, int height)public void fillRoundRect(int x, int y,

int width, int height,int arcWidth, int arcHeight)

O método drawRect desenha um retângulo com o canto superior esquerdo nas coordenadas definidas pelos parâmetros x e y e com área definida em width+1 e height+1. Os mesmos parâmetros estão no método drawRoundRect. Os parâmetros adicionais arcWidth e arcHeight são os diâmetros horizontal e vertical do arco dos quatro cantos.

Note que a definição dos métodos drawRect e drawRoundRect especificam que o tamanho do retângulo desenhado na tela é width+1 e a altura é height+1. Isto não é muito intuitivo, entretanto é desta forma que estes métodos foram definidos para as especificações de MIDP.

Para agravar esta inconsistência de adicionar 1 ao tamanho real, os métodos fillRect e fillRoundRect preenchem um retângulo de área especificada por width e height. Devido a esta inconsistência pode-se colocar os mesmos parâmetros para os métodos drawRect, fillRect, drawRoundRect e fillRoundRect. As bordas da direita e da parte inferior do retângulo desenhado pelo método drawRect estarão além da área preenchida por fillRect.

// use tinta preta para drawRectg.setColor(0, 0, 0);g.drawRect(8, 8, 64, 32);// use tinta amarela para fillRect// para mostrar a diferença entre drawRect e fillRectg.setColor(255, 255, 0);g.fillRect(8, 8, 64, 32);

Desenvolvimento de Aplicações Móveis 14

Page 60: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

Figura 7: Saída usando os mesmos parâmetros para drawRect e fillRect

// Define a cor da caneta para preto g.setColor(0, 0, 0); // Desenha um retângulo na posição inicial 4 e 8 com largura 88 e altura 44// o retângulo superior esquerdog.drawRect(4,8,88,44);// Desenha um retângulo arredondado no canto superior direitog.drawRoundRect(108,8,88,44,18,18);// Desenha um retângulo no canto inferior esquerdog.fillRect(4,58,88,44);// Desenha um retângulo no canto inferior direitog.fillRoundRect(108,58,88,44,18,18);

Figura 8: drawRect(), fillRect(), drawRoundRect() e fillRoundRect()

3.9. Desenhando Arcos

Os métodos para desenhar arcos circulares ou elípticos são:

Desenvolvimento de Aplicações Móveis 15

Page 61: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

public void drawArc( int x, int y, int largura, int altura, int anguloInic, int anguloArco)

desenhar um arco com centro em (x,y) e dimensões (largura+1 x altura+1). O arco desenhado inicia-se em anguloInic e se estende por anguloArco graus. 0 (zero) grau está na posição 3 horas

public void fillArc( int x, int y, int largura, int altura, int anguloInic, int anguloArco)

desenhar um um arco circular ou elíptico com toda a sua área coberta com a cor atual

g.setColor(255, 0, 0);g.drawArc(18, 18, 50, 50, 0, 360); // desenha um círculog.setColor(0, 255, 0);g.drawArc(40, 40, 100, 120, 0, 180);g.setColor(0, 0, 255);g.fillArc(100, 200, 80, 100, 0, 90);

Figura 9: Saída da chamada aos métodos drawArc e fillArc

3.10. Desenhando imagens

Imagens são desenhadas usando o método drawImage() que possui a seguinte assinatura:

public void drawImage(Image img, int x, int y, int anchor)Atenção: No NetBeans as imagens devem ser colocadas na pasta src do projeto.

Do mesmo modo que no método drawString(), os parâmetros x e y são as coordenadas do ponto de âncora. A diferença é que a constante vertical da âncora é VCENTER em vez de BASELINE.

A âncora deve ser uma combinação de uma constante horizontal (LEFT, HCENTER ou RIGHT) e de uma vertical (TOP, VCENTER ou BOTTOM). As constantes horizontal e vertical devem ser combinadas usando o operador de bit OR (|). Isto significa que desenhar texto relativo ao centro vertical e ao centro horizontal da imagem requer uma âncora de valor VCENTER | HCENTER.

Desenvolvimento de Aplicações Móveis 16

Page 62: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

TOP | LEFT

BOTTOM | HCENTER

BOTTOM | LEFT BOTTOM | RIGHT

TOP | RIGHT

TOP | HCENTER

VCENTER | LEFT VCENTER | RIGHT

VCENTER | HCENTER

Figura 10: Pontos de âncora da imagem

try { Image image = Image.createImage("/jedi.png"); g.drawImage(image, getWidth()/2, getHeight()/2, Graphics.VCENTER | Graphics.HCENTER);} catch (Exception e){}

Figura 11: Saída do método drawImage()

3.11. Programa Final

Iremos combinar as idéias aprendidas nesta lição para obtermos o logo do JEDI na tela do celular.

import javax.microedition.midlet.*;import javax.microedition.lcdui.*;public class LogoMidlet extends MIDlet { private Display display; private LogoJedi canvas;

Desenvolvimento de Aplicações Móveis 17

Page 63: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

public void startApp() { if (display == null){ canvas = new LogoJedi(this); display = Display.getDisplay(this); } display.setCurrent(canvas); } public void pauseApp() { } public void destroyApp(boolean unconditional) { } protected void Quit(){ destroyApp(true); notifyDestroyed(); }}class LogoJedi extends Canvas implements CommandListener { private Command exitCommand = new Command("Exit", Command.EXIT, 0); private LogoMidlet midlet; private String text; public LogoJedi(LogoMidlet midlet) { this.midlet = midlet; addCommand(exitCommand); setCommandListener(this); } protected void paint(Graphics g) { // Limpa a janela g.setColor(255, 255, 255 ); g.fillRect(0, 0, getWidth(), getHeight()); // Imagem try { Image image = Image.createImage("/jedi.png"); g.drawImage(image, getWidth()/2, 80, Graphics.VCENTER | Graphics.HCENTER); } catch (Exception e){ } // Texto g.setColor(255, 0, 0); // vermelho Font f = Font.getFont(Font.FACE_PROPORTIONAL, Font.STYLE_BOLD, Font.SIZE_LARGE); g.setFont(f); g.drawString("JEDI", getWidth()/2, getHeight()/2, Graphics.TOP | Graphics.HCENTER); int tamFont = f.getHeight(); g.setColor(0, 0, 255); // azul g.drawLine(20, getHeight()/2+tamFont, getWidth()-20, getHeight()/2+tamFont); f = Font.getFont(Font.FACE_PROPORTIONAL, Font.STYLE_PLAIN, Font.SIZE_SMALL); g.setFont(f); g.drawString("Java Education & Development Initiative", getWidth()/2, getHeight()/2+tamFont+3, Graphics.TOP | Graphics.HCENTER); } public void commandAction(Command c, Displayable d) { if (c == exitCommand){ midlet.Quit(); } }}

Desenvolvimento de Aplicações Móveis 18

Page 64: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

4. Exercícios

4.1. Códigos de Teclas

Criar um MIDlet que mostre o código e o nome da tecla que foi pressionada pelo usuário. Utilizar um Canvas para mostrar este código e o nome no centro da tela.

Desenvolvimento de Aplicações Móveis 19

Page 65: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

Módulo 5Desenvolvimento de Aplicações Móveis

Lição 5Sistema de Gerenciamento de Registro

Versão 1.0 - Set/2007

Page 66: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

1. Objetivos

MIDP fornece uma biblioteca de componentes onde os programas podem salvar os dados da aplicação no dispositivo de modo físico. O Sistema de Gerenciamento de Registro do MIDP é o meio pelo qual as MIDlets podem armazenar dados através de chamadas MIDlet. Os dados são armazenados na memória não-volátil do dispositivo, ou seja, não serão perdidos mesmo que o programa seja finalizado ou o aparelho seja desligado.

O Sistema de Gerenciamento de Registro é um sistema de banco de dados orientados a registro para dispositivos MIDP. Um registro neste banco de dados é simplesmente um array de bytes com um índice.

Ao final desta lição, o estudante será capaz de:

• Entender o conceito de RecordStore• Criar ou abrir um RecordStore• Adicionar, recuperar, atualizar e excluir registros• Fechar um RecordStore• Enumerar registros utilizando um RecordEnumerator• Criar um RecordComparator• Criar um RecordFilter

Desenvolvimento de Aplicações Móveis 4

Page 67: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

2. RecordStore

Record Store é uma coleção de registros, a classe é encontrada no pacote javax.microedition.rms. Identificadores de registro (Record ID) em um banco de dados são únicos. Esses identificadores são automaticamente alocados no momento da criação do registro e funcionam como um índice ou chave primária. São atribuídos sequencialmente, sendo que o primeiro ID de cada banco de dados possui o valor igual a 1 (um).

Quando um registro é excluído, seu identificador não será reutilizado. Se criarmos quatro registros e excluirmos o quarto, o próximo identificador que o sistema atribuirá será igual a 5 (ver Figura).

Record ID Array de bytes

1 Dado do registro #1

2 Dado do registro #2

3 Dado do registro #3

5 Dado do registro #5

Aplicativos MIDlets podem criar mais de um objeto RecordStore. O nome do RecordStore deve ser único dentro de uma suite MIDlet. São sensíveis ao contexto (maiúsculas diferentes de minúsculas) e devem possuir um tamanho máximo de 32 caracteres.

Quando uma aplicação MIDlet é eliminada de um dispositivo, todos os RecordStore associados a esta aplicação também serão eliminados.

2.1. Criando ou Abrindo um RecordStore

Os métodos listados abaixo criam ou abrem para uso um RecordStore:

static RecordStore openRecordStore( String recordStoreName, boolean createIfNecessary) static RecordStore openRecordStore( String recordStoreName, boolean createIfNecessary, int authmode, boolean writable) static RecordStore openRecordStore( String recordStoreName, String vendorName, String suiteName)

Caso o parâmetro createIfNecessary possuir o valor true e o RecordStore não existir, este será automaticamente criado. Se o parâmetro possuir o valor false e o RecordStore não existir, uma exceção do tipo RecordStoreNotFoundException será lançada.

O parâmetro authmod poderá assumir um dos seguintes atributos constantes existentes: RecordStore.AUTHMODE_PRIVATE ou RecordStore.AUTHMODE_ANY. Utilizando o primeiro atributo o RecordStore será acessível apenas pela aplicação MIDlet que o criou. Utilizando o segundo atributo o RecordStore será acessível por qualquer aplicação MIDlet. O modo de acesso é especificado pelo parâmetro lógico writable. Para permitir que outros MIDlets (fora do aplicativo que o criou) armazenem ou leiam dados neste Record Store, este parâmetro deverá ser informado com o valor true.

Utilizando a primeira forma do método openReacordStore() o resultado obtido é que o RecordStore será acessível somente aos MIDlets da mesma aplicação (o valor do atributo authmode terá o mesmo valor da constante AUTHMODE_PRIVATE).

Para abrir um RecordStore existente a partir de uma aplicação MIDlet diferente, a terceira forma do método openRecordStore é utilizada. Os parâmetros vendorName e suiteName deverão ser

Desenvolvimento de Aplicações Móveis 5

Page 68: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

especificados contendo o nome do desenvolvedor e o nome do aplicativo.

Se o RecordStore já estiver aberto, estes métodos irão retornar sua referência deste. O sistema mantém armazenado quantas vezes foram abertos os RecordStore. É obrigatório que RecordStore seja fechado o mesmo número de vezes que tenha sido aberto.

2.2. Adicionando Registros

O seguinte método é responsável pelas adições de novos registros em um RecordStore:

int addRecord(byte[] data, int offset, int numBytes)

O método addRecord criará um novo registro no banco de dados e retornará o seu identificador (Record ID). As informações recebidas como parâmetro neste método são:

1. Um array de bytes contendo os dados a serem armazenados

2. Um atributo inteiro contendo a posição inicial do array enviado

3. A quantidade total de elementos do array

2.3. Recuperando Registros

Os seguintes métodos são responsáveis pelas buscas de dados em um Record Store:

byte[] getRecord( int recordId) int getRecord( int recordId, byte[] buffer, int offset) int getRecordSize( int recordId)

A primeira forma do método getRecord devolve uma cópia dos dados armazenados no registro com a Record ID especificada pelo parâmetro. A segunda forma copiará os dados no parâmetro (array de bytes) fornecido Ao utilizar esta forma, o array de bytes precisa estar previamente alocado. Caso o tamanho do registro seja maior que o tamanho do parâmetro uma exceção ArrayIndexOutOfBoundsException será lançada. O método getRecordSize é utilizado de modo a obter o tamanho do registro que será lido.

2.4. Modificando Registros

Não se pode modificar somente uma parte do registro. Para modificar um registro é necessário:

1. Ler o registro utilizando o método getRecord2. Modificar o registro na memória3. Chamar o método setRecord para modificar os dados do registro

O método setRecord possui a seguinte assinatura:

void setRecord( int recordId, byte[] newData, int offset, int numBytes)

2.5. Eliminando Registros

O seguinte método é responsável pelas eliminações dos dados em um RecordStore:

void deleteRecord( int recordId)

Quando um registro é eliminado, o ID deste registro não será reutilizado para as próximas inclusões. Isto significa que podem ocorrer buracos entre os registros. Deste modo não é aconselhável utilizar um incrementador para listar todos os registros de um Record Store. Um

Desenvolvimento de Aplicações Móveis 6

Page 69: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

RecordEnumerator deve ser utilizado para percorrer a lista de registros guardados.

2.6. Fechando um RecordStore

O seguinte método é responsável pelo fechamento de um RecordStore:

void closeRecordStore()

Ao chamar o método closeRecordStore(), o RecordStore não será fechado até que seu valor seja idêntico ao número de chamadas do método openRecordStore(). O sistema armazena o número de vezes que um Record Store foi aberto. Caso o número de chamadas ao método closeRecordStore() sejam superiores ao número de chamadas ao método openRecordStore(), será disparada uma exceção do tipo RecordStoreNotOpenException.

Este trecho de código mostra um exemplo de um MIDlet simples que exemplifica a criar, adição e localização de dados em um RecordStore:

// Abre ou Cria um RecordStore com o nome "RmsExample1"recStore = RecordStore.openRecordStore("RmsExample1", true); // Lê o conteúdo do RecordStorefor (int recId=1; recId <= recStore.getNumRecords(); recId++){ // O método getRecord returna o tamanho do registro recLength = recStore.getRecord(recId, data, 0); // Converte para String um array de bytes String item = new String(data, 0, recLength); ...}// Este será o dado a ser guardadoString newItem = "Record #" + recStore.getNextRecordID(); // Converte a String para o array de bytesbyte[] bytes = newItem.getBytes(); // Grava o dado no RecordStorerecStore.addRecord(bytes, 0, bytes.length);

Dicas de Programação:

1.O Registro começa com o valor de ID igual a 1, e não 0. Deve-se tomar cuidado ao se utilizar laços.

2.É melhor utilizar um RecordEnumerator do que um índice incrementado (como neste exemplo). Registros eliminados ainda serão lidos por este exemplo e causará uma exceção do tipo InvalidRecordIDException.

2.7. Obtendo uma Lista de RecordStore de uma aplicação MIDlet

O seguinte método é responsável pela obtenção de uma lista de RecordStore existente:

static String [] listRecordStores()

O método retorna um conjunto de nomes de RecordStore que foram criados pela aplicação MIDlet. Se a aplicação não possuir nenhum RecordStore é retornado o valor null.

String[] storeNames = RecordStore.listRecordStores();System.out.println("RecordStore for this MIDlet suite:");for (int i=0; storeNames != null && i < storeNames.length; i++) { System.out.println(storeNames[i]);}

Este é um exemplo de saída:

Desenvolvimento de Aplicações Móveis 7

Page 70: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

Record Stores for this MIDlet suite:PrefsRmsExample1RmsExample2

A ordem dos nomes retornados não está definida e é dependente da implementação. Então, ao se desejar exibir os nomes ordenados alfabeticamente, primeiro deve-se realizar uma ordenação deste array.

2.8. Guardando Tipos Primitivos de Java

Até o momento, os dados que temos gravados e lidos no RecordStore são Strings. CLDC inclui as classes padrões para manipulação de tipos primitivos. Estas classes são da biblioteca padrão da Plataforma Java Standard Edition (Java SE).

Pode-se gravar tipos primitivos combinando as classes ByteArrayOutputStream e DataOutputStream. Para ler tipos primitivos (int, long, short, char, boolean, etc) pode-se também utilizar as classes ByteArrayInputStream e DataInputStream.

ByteArrayOutputStream out = new ByteArrayOutputStream();DataOutputStream dOut = new DataOutputStream(out); // Armazenando um inteirodOut.writeInt(recStore.getNextRecordID() * recStore.getNextRecordID()); // Armazenando uma StringdOut.writeUTF("Record #" + recStore.getNextRecordID()); // Transformando para um array de bytes byte[] bytes = out.toByteArray(); // Armazenando os dados no Record StorerecStore.addRecord(bytes, 0, bytes.length);...// Obtendo o próximo registrobyte[] recBytes = enumerator.nextRecord(); // Para resgatar os valoresByteArrayInputStream in = new ByteArrayInputStream(recBytes);DataInputStream dIn = new DataInputStream(in);int count = dIn.readInt();String item = dIn.readUTF();

2.9. Outros métodos para um RecordStore

Os seguintes métodos podem ser utilizados para obter dados de um RecordStore:

long getLastModified() int getVersion()

O sistema armazena a informação de quando um Record Store foi modificado pela última vez. Este valor pode ser obtido através do método getLastModified() e retorna um valor do tipo long, que poderá ser utilizado pelo método System.currentTimeMillis().

O RecordStore mantém a informação da versão que pode ser obtida através do método getVersion(). Toda vez em que um registro é modificado, seu número de versão é atualizado. Utilizando-se qualquer um dos métodos addRecord, setRecord e deleteRecord o número de versão do objeto será incrementado.

Outros métodos que podem ser utilizados são:

static void deleteRecordStore( String nomeRecordStore) Eliminar a RecordStore que contenha o nome fornecido

String getName() Retornar o nome do RecordStore

Desenvolvimento de Aplicações Móveis 8

Page 71: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

int getNextRecordID() Retornar o recordId do próximo registro a ser adicionado ao objeto RecordStore

int getNumRecords() Retornar o número de registros atualmente no RecordStoreint getSize() Retornar a quantidade de bytes ocupados em um RecordStoreint getSizeAvailable() Retornar a quantidade de bytes disponíveis em um RecordStorevoid setMode( int authmode, boolean writable)

Modificar o modo de acesso de um RecordStore

Desenvolvimento de Aplicações Móveis 9

Page 72: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

3. Enumeração de Registro

Percorrer registros incrementando um índice é uma forma ineficiente de agir. O RecordStore pode ter seus registros eliminados que geram buracos no RecordId.

A utilização de um RecordEnumeration resolve este problema sem ter de tratar os registros excluídos. É possível também ordenar um objeto do tipo RecordEnumeration utilizando-se o método comparator(). Utilizando-se o método filter(), pode-se saltar os registros que não são importantes para o resultado.

RecordEnumeration enumerateRecords( RecordFilter filter, RecordComparator comparator, boolean keepUpdated)

O método enumerateRecords de um RecordStore retornará um objeto do tipo RecordEnumeration, no qual é permitido obter todos os registros de um RecordStore. Essa é a maneira recomendada para percorrer todos os registros armazenados. Iremos discutir os objetos filter e comparator nas próximas seções.

O modo mais simples para utilizar esse método é informar o valor null para os parâmetros filter e comparator. Obteremos como retorno da execução deste método um objeto do tipo RecordEnumeration de todos os registros do Record Store ordenados de uma maneira indefinida.

// Abrir ou criar um Record Store com o nome "RmsExample2" recStore = RecordStore.openRecordStore("RmsExample2", true); // Carregar o conteúdo do Record Store RecordEnumeration enumerator = recStore.enumerateRecords(null, null, false); while (enumerator.hasNextElement()){ // Obter o próximo registro e converter um array de byte em String String item = new String(enumerator.nextRecord()); // Realiza qualquer instrução com o dado ... }

Desenvolvimento de Aplicações Móveis 10

Page 73: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

4. Comparador de Registros

A ordenação de um objeto do tipo RecordEnumeration pode ser definida utilizando-se um RecordComparator. Um RecordComparator é passado para o método enumerateRecords. Caso seja necessário ordenar um objeto do tipo RecordEnumeration, isso pode ser feito definindo-se um objeto do tipo RecordComparator e enviando-o como o segundo parâmetro para o método enumerateRecords.

int compare(byte[] reg1, byte[] reg2)

Para criar um RecordComparator, é preciso primeiro implementar a interface RecordComparator. Essa interface define um único método compare(byte[] reg1, byte[] reg2). Esse método precisa retornar RecordComparator.FOLLOWS ou RecordComparator.PRECEDES se reg1 procede ou antecede reg2 na ordem, respectivamente. RecordComparator.EQUIVALENT pode ser retornado se reg1 for igual a reg2 na ordem.

// Criar uma enumeration, ordenada alfabeticamente RecordEnumeration enumerator = recStore.enumerateRecords( null, new AlphaOrder(), false); // Classe que ordena alfabeticamente class AlphaOrder implements RecordComparator { public int compare(byte[] reg1, byte[] reg2){ String registro1 = new String(reg1).toUpperCase(); String registro2 = new String(reg2).toUpperCase(); if (registro1.compareTo(registro2) < 0){ return(RecordComparator.PRECEDES); } else { if (registro1.compareTo(registro2) > 0){ return(RecordComparator.FOLLOWS); } else { return(RecordComparator.EQUIVALENT); } } } }

Desenvolvimento de Aplicações Móveis 11

Page 74: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

5. Filtro de Registros

Os exemplos que vimos até o momento somente percorrem e lêem todos registros de um Record Store. Entretanto, podemos utilizar um filter para obtermos somente os registros que são necessários.

A classe necessita implementar o método match() para selecionar somente os registros válidos em um determinado contexto.

boolean matches(byte[] candidate)

O retorno é um atributo do tipo lógico que deve conter o valor true caso o registro seja compatível com o critério definido. Caso contrário é retornado false.

public boolean matches(byte[] candidate){ boolean resultado = false; try { ByteArrayInputStream bin = new ByteArrayInputStream(candidate); DataInputStream dIn = new DataInputStream(bin); int count = dIn.readInt(); String item = dIn.readUTF(); // Retornar somente registros com o conteúdo terminado com 0 resultado = item.endsWith("0"); } catch (Exception e) { } return(resultado);}

Desenvolvimento de Aplicações Móveis 12

Page 75: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

6. Consumo de Combustível

Iremos ajuntar algumas idéias aprendidas até o momento e montar um aplicativo prático para controlar o consumo de combustível do nosso carro.

Ao pensarmos em aplicativos para aparelhos móveis devemos ter em mente as seguintes regras:

1. Praticidade

2. Facilidade

O usuário estará no posto abastecendo o carro. Ao acessar o aplicativo precisamos obter duas informações: a quilometragem atual do veículo e a quantidade de combustível inserida. Neste primeiro registro ainda não teremos dados suficientes para o cálculo do consumo, entretanto, a partir do segundo registro já poderemos calcular o consumo, obtido pela fórmula:

(quilometragem atual – quilometragem anterior) / quantidade combustível

Uma outra idéia interessante é guardar somente as últimas 11 entradas, deste modo mostraremos as 10 últimas médias de consumo. Antes de verificar as classes descritas abaixo, tente resolver este aplicativo.

A primeira classe chamada PrincipalMidlet. Conforme vimos anteriormente, o método startApp() fará a chamada a um objeto do tipo Canvas.

import javax.microedition.midlet.*;import javax.microedition.lcdui.*;public class PrincipalMidlet extends MIDlet { private MenuCanvas canvas; public Display display; public void startApp() { if (display == null) { canvas = new MenuCanvas(this); display = Display.getDisplay(this); } display.setCurrent(canvas); } protected void pauseApp() { } protected void destroyApp(boolean arg0) throws MIDletStateChangeException { }}

A segunda classe, chamada MenuCanvas, do tipo Canvas, conterá toda a regra de negócio.

import javax.microedition.lcdui.*;import javax.microedition.midlet.MIDletStateChangeException;import javax.microedition.rms.*;public class MenuCanvas extends Canvas implements CommandListener { private PrincipalMidlet pai; private InsertForm form; private byte opc = 0; private Command exitCmd = new Command("Exit", Command.EXIT, 0); private Command insertCmd = new Command("Insert", Command.OK, 1); private Command reportCmd = new Command("Report", Command.OK, 1); // Comandos para o Form private Command backCmd = new Command("Back", Command.BACK, 2); private Command saveCmd = new Command("Save", Command.OK, 1); // Atributos para o Registro private String regGas; private RecordStore rsGas; public MenuCanvas(PrincipalMidlet pai) {

Desenvolvimento de Aplicações Móveis 13

Page 76: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

// Cria ou abre o registro try { rsGas = RecordStore.openRecordStore("Gasolina", true); } catch (RecordStoreException ex) { ex.printStackTrace(); } this.pai = pai; setCommandListener(this); addCommand(exitCmd); addCommand(insertCmd); addCommand(reportCmd); } public void paint(Graphics g) { g.setColor(255, 255, 255); g.fillRect(0, 0, getWidth(), getHeight()); g.setColor(0, 64, 128); switch (opc) { case 0: g.drawString("Principal Menu", 0, 0, Graphics.TOP | Graphics.LEFT); g.setColor(0, 114, 168); g.drawString("Use this program for the control", 0, 24, Graphics.TOP | Graphics.LEFT); g.drawString("the consumption of gasoline in your car", 0, 36, Graphics.TOP | Graphics.LEFT); g.drawString("Options:", 0, 64, Graphics.TOP | Graphics.LEFT); g.drawString("INSERT - Use for add record Km/Lt", 0, 76, Graphics.TOP | Graphics.LEFT); g.drawString("REPORT - Use for list the 10 last consumer", 0, 88, Graphics.TOP | Graphics.LEFT); g.drawString("Fernando Anselmo", 0, 112, Graphics.TOP | Graphics.LEFT); break; case 1: int lin = 0; g.drawString("Report Option", 0, lin, Graphics.TOP | Graphics.LEFT); lin += 14; g.drawString("Your 10 last consumes is...", 0, lin, Graphics.TOP | Graphics.LEFT); lin += 12; int od1 = 0; int od2 = 0; double gas = 0.0; g.setColor(0, 114, 168); try { if (rsGas.getNumRecords() > 1) { for (int recId = 1; recId < rsGas.getNumRecords(); recId++) { regGas = new String(rsGas.getRecord(recId)); od1 = Integer.parseInt(regGas.substring(0, regGas.indexOf("|"))); gas = Double.parseDouble(regGas.substring( regGas.indexOf("|") + 1)); regGas = new String(rsGas.getRecord(recId + 1)); od2 = Integer.parseInt(regGas.substring(0, regGas.indexOf("|"))); lin += 15; g.drawString(recId + ") " + ((od2 - od1) / gas) + " Km/Lt", 0, lin, Graphics.TOP | Graphics.LEFT); } } } catch (RecordStoreException ex) { ex.printStackTrace(); } break; } } public void commandAction(Command command, Displayable displayable) { if (command == exitCmd) { try { rsGas.closeRecordStore();

Desenvolvimento de Aplicações Móveis 14

Page 77: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

pai.destroyApp(true); pai.notifyDestroyed(); } catch (RecordStoreException ex) { ex.printStackTrace(); } catch (MIDletStateChangeException ex) { ex.printStackTrace(); } } else if (command == insertCmd) { repaint(); form = new InsertForm("Insert Option"); pai.display.setCurrent(form); } else if (command == reportCmd) { opc = 1; repaint(); } else if (command == backCmd) { pai.display.setCurrent(this); opc = 0; repaint(); } else if (command == saveCmd) { regGas = form.getRegGas(); byte[] data; try { if (rsGas.getNumRecords() == 11) { for (int recId = 1; recId < rsGas.getNumRecords(); recId++) { data = rsGas.getRecord(recId + 1); rsGas.setRecord(recId, data, 0, data.length); } data = regGas.getBytes(); rsGas.setRecord(11, data, 0, data.length); } else { data = regGas.getBytes(); rsGas.addRecord(data, 0, data.length); } } catch (RecordStoreException ex) { ex.printStackTrace(); } pai.display.setCurrent(this); opc = 0; repaint(); } } class InsertForm extends Form { private TextField QTDGAS; private TextField ODOMETER; public InsertForm(String title) { super(title); addCommand(backCmd); addCommand(saveCmd); setCommandListener(MenuCanvas.this); ODOMETER = new TextField("Odometer (Kilometer):", "", 64, TextField.NUMERIC); QTDGAS = new TextField("Gasoline (Liter):", "", 64, TextField.DECIMAL); this.append(new StringItem("Inform your consumption", "")); this.append(ODOMETER); this.append(QTDGAS); } public String getRegGas() { return ODOMETER.getString() + "|" + QTDGAS.getString(); } }}

Começaremos pelo construtor que montará a janela principal. Observe que o atributo opc do tipo byte possuirá o controle sobre qual visão da aplicação temos. O construtor também inicializa o objeto do tipo RecordStore (chamado rsGas). Logo em seguida o método paint será chamado e

Desenvolvimento de Aplicações Móveis 15

Page 78: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

mostrará a seguinte janela:

Figura 1: Janela do Menu Principal

Caso o comando seja “Insert”, passaremos para o método commandAction. Neste momento montaremos um objeto da classe Form e a definiremos como principal. Montaremos com este formulário a seguinte janela:

Figura 2: Janela da Opção de Inclusão

O usuário entrará com a informação da quantidade de quilômetros percorridos pelo carro até o momento e a quantidade de litros abastecidos. Pode-se escolher a opção “Save” para salvar o registro, ou “Back” para retornar ao menu principal.

Caso seja selecionada a opção “Save”, realizaremos a verificação se já foram inseridos 11 registros. Em caso afirmativo, movimentaremos o registro que ocupa a segunda posição para a primeira, o que ocupa a terceira posição para a segunda e deste modo sucessivamente até que se libere a décima primeira posição, onde guardaremos este novo registro. Em caso negativo, simplesmente inserimos mais um registro ao RecordStore.

No menu principal, caso o comando seja “Report”, passaremos para o método commandAction,

Desenvolvimento de Aplicações Móveis 16

Page 79: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

mudando o atributo opc e montamos agora a seguinte janela:

Figura 3: Janela da Opção de Relatório

Agora fica por conta do método paint localizar os registros informados e realizar o cálculo conforme vimos, lembrando que o método indexOf(String) localiza uma determinada posição dentro de um objeto String e o método substring(int1, int2) localiza uma determinada posição e retorna todos os caracteres a partir desta enquanto a posição seja menor que o segundo valor.

Note que este projeto está bem compacto e ainda permite diversas melhorias, tais como:

● Imagens

● Opções para o usuário selecionar quantos registro deseja armazenar

● Um gráfico para mostrar o consumo ao invés de informação textual

Então, utilize-o como aplicativo base para praticar.

Desenvolvimento de Aplicações Móveis 17

Page 80: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

7. Exercícios

7.1. Armazenar Preferências

Criar um aplicativo MIDlet que possa armazenar as preferências de um programa. Este aplicativo irá armazenar as preferências em um objeto do tipo RecordStore. Cada registro irá conter o nome de uma variável e seu valor. Cada conjunto variável e valor será armazenado em um único registro.

Dica: Pode-se implementar os métodos:

public String ler(RecordStore recStore, String nome, String valorPadrao);public void escrever(RecordStore recStore, String nome, String valor);

Desenvolvimento de Aplicações Móveis 18

Page 81: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

Módulo 5Desenvolvimento de Aplicações Móveis

Lição 6Redes

Versão 1.0 - Set/2007

Page 82: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

1. Objetivos

Nesta lição, iremos estudar como acessar redes utilizando MIDlets.

Ao final desta lição, o estudante será capaz de:

• Descrever o Framework Genérico de Conexão e como pode ser usado para suportar diferentes métodos de conexão

• Especificar argumentos de conexão usando o formato de endereço URL do GCF• Criar conexões HTTP/HTTPS• Criar MIDlets usando soquetes TCP e datagramas UDP

Desenvolvimento de Aplicações Móveis 4

Page 83: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

2. Framework Genérico de Conexão

O Framework Genérico de Conexão suporta as conexões baseadas em pacotes (através de Soquetes) e baseadas em stream (através de Datagramas). Como o nome diz, este framework provê uma API básica para conexões em CLDC. Determina uma base comum para conexões como HTTP, soquetes e datagramas. Mesmo bluetooth e serial I/O tem um lugar neste framework. Fornece um conjunto genérico e comum da API que abstrai todos os tipos de conexões. Deve-se notar que nem todos os tipos de conexão devem ser requeridos para ser implementados pelos dispositivos MIDP.

2.1. Hierarquia da Interface GCF

A hierarquia extensível da interface do GCF torna possível a generalização. Um novo tipo de conexão pode ser adicionado a este framework através da extensão desta hierarquia.

Figura 1: Hierarquia da Interface GCF

2.2. A URL de Conexão GCF

Argumentos de conexão são especificados usando o formato de endereçamento:

scheme://username:password@host:port/path;parameters

1. scheme (esquema) é o protocolo ou método de conexão. Exemplos de esquemas são: http, ftp e https

2. username (nome do usuário) é opcional, entretanto, caso seja especificado, um @ deve preceder o host

3. password (senha do usuário) é opcional e pode ser especificada somente se o username estiver presente. Se a password estiver presente, deve estar separada do username por dois pontos (:)

Desenvolvimento de Aplicações Móveis 5

Page 84: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

4. host (domínio) este argumento é obrigatório. Pode ser um hostname, um nome completo no domínio (FQDN) ou o endereço IP do host alvo.

5. port (porta) este argumento é opcional. Caso não seja especificado, a porta padrão para o esquema será utilizada.

6. path (caminho)

7. parameters (argumentos) este é opcional, mas deve estar precedido por ponto e vírgula quando presente

Se utilizarmos colchetes para definir os argumentos opcionais neste formato de endereçamento, poderemos expressar da seguinte forma:

scheme://[username[:password]@]host[:port]/path[;parameters]

O Uniform Resource Indicator (URI) está definido no RFC 2396, que é a base para este formato de endereçamento. No MIDP 2.0, somente os esquemas "http" e "https" devem ser implementados por estes dispositivos.

Desenvolvimento de Aplicações Móveis 6

Page 85: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

3. Conexão HTTP

3.1. O Protocolo HTTP

HTTP significa Protocolo de Transporte de Hiper Texto. Este é o protocolo utilizado para transferir páginas da WEB de seus servidores (ex. www.sun.com) para os WEB Browsers. O cliente (WEB Browser) requisita uma página, especificando o seu caminho com os modelos do tipo "GET" ou "POST".

Para o modelo "GET", argumentos são especificados e embutidos na URL. Por exemplo, para passar um atributo com o nome "id" e valor 100 a página "index.jsp", a URL é especificada da seguinte forma: "http://hostname/index.jsp?id=100". Argumentos adicionais são separados pelo simbolo &, por exemplo: "http://hostname/index.jsp?id=100&page=2".

Quando o modelo "POST" é utilizado, argumentos não fazem parte da URL, mas são enviados em linhas diferentes após o comando POST.

Cliente / Navegador WEB Servidor HTTPGET /index.jsp?id=100 HTTP/1.1 HTTP/1.1 200 OK

Server: Apache-Coyote/1.1Content-Type: text/html;charset=ISO-8859-1Date: Wed, 18 Jun 2005 14:09:31 GMTConnection: close<html> <head> <title>Test Page</title> </head> <body> <h1 align="center">Test Page</h1> </body></html>

Figura 2: Exemplo de Transação HTTP GET

Cliente / Navegador WEB Servidor HTTPGET /non-existent.html HTTP/1.0 HTTP/1.1 404 /non-existent.html

Server: Apache-Coyote/1.1Content-Type: text/html;charset=utf-8Content-Length: 983Date: Mon, 11 Jul 2005 13:21:01 GMTConnection: close<html><head><title>Apache Tomcat/5.5.7 - Error report</title><style>...<body><h1>HTTP Status 404</h1>...The requested resource (non-existent.html) is not available....</body></html>

Figura 3: Exemplo de transação HTTP GET com um response erro

3.2. Criando uma conexão HTTP

Podemos abrir uma conexão HTTP usando o método Connector.open() e fazer um casting com uma das seguintes interfaces: StreamConnection, ContentConnection ou HTTPConnection. Entretanto, com as interfaces StreamConnection e ContentConnection podemos especificar e derivar parâmetros específicos do HTTP resultante.

Quando se utiliza a StreamConnection, o tamanho da resposta não pode ser determinado previamente. Com a interface ContentConnection ou HTTPConnection existe a possibilidade de se determinar o tamanho da resposta. Porém, o tamanho não está sempre disponível, então o

Desenvolvimento de Aplicações Móveis 7

Page 86: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

programa deverá que ser capaz de recorrer a outros meios para obter a resposta sem o conhecimento prévio do tamanho.

HttpConnection connection = null;InputStream iStream = null;byte[] data = null; try { connection = (HttpConnection) Connector.open("http://www.sun.com/"); int code = connection.getResponseCode(); switch (code) { case HttpConnection.HTTP_OK: iStream = connection.openInputStream(); int length = (int) connection.getLength(); if (length > 0){ data = new byte[length]; int totalBytes = 0; int bytesRead = 0; while ((totalBytes < length) && (bytesRead > 0)) { bytesRead = iStream.read( data, totalBytes, length - totalBytes); if (bytesRead > 0){ totalBytes += bytesRead; } } } else { // Tamanho não é conhecido, ler por caracter ... } break; default: break; } ...

3.3. Controlando Redirecionamentos HTTP

Algumas vezes o servidor redireciona o navegador do cliente para outras páginas WEB através de uma resposta que pode ser através de uma HTTP_MOVED_PERM (301), HTTP_MOVED_TEMP (302), HTTP_SEE_OTHER (303) ou HTTP_TEMP_REDIRECT (307) ao invés da resposta comum HTTP_OK. O programa terá de ser capaz de detectar isso utilizando o método getResponseCode(), obter a nova URI do cabeçalho utilizando o método getHeaderField("Localização") e recuperar esse documento na nova localização.

int code = connection.getResponseCode();switch(code){ case HttpConnection.HTTP_MOVED_PERM: case HttpConnection.HTTP_MOVED_TEMP: case HttpConnection.HTTP_SEE_OTHER: case HttpConnection.HTTP_TEMP_REDIRECT: String newUrl = conn.getHeaderField("Location"); ...

Desenvolvimento de Aplicações Móveis 8

Page 87: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

4. Conexões HTTPS

HTTPS é um modelo HTTP sobre uma conexão segura de transporte. A abertura de uma conexão do tipo HTTPS é realizada de forma idêntica a abrir uma conexão do tipo HTTP. A única diferença é que a URL é passada para Connector.open() e o resultado moldado para uma variável da classe HttpsConnection.

Um tipo adicional de exceção pode ser lançada por um método Connector.open() ao invés das exceções comuns IllegalArgumentException, ConnectionNotFoundException, java.io.IOException e SecurityException. Uma exceção do tipo CertificateException pode ser disparada por causa de falhas no certificado.

import javax.microedition.io.*;HttpsConnection connection = null;InputStream iStream = null;byte[] data = null;try { connection = (HttpsConnection) Connector.open("https://www.sun.com/"); int code = connection.getResponseCode(); ...} catch (CertificateException ce){ switch (ce.getReason()){ case CertificateException.EXPIRED: ... }}

Todos as constantes listadas a seguir foram retiradas da especificação MIDP 2.0 – JSR 118 e são do tipo byte estáticas.

BAD_EXTENSIONS Indicar que um certificado possui extensões críticas desconhecidas

BROKEN_CHAIN Indicar que um certificado numa cadeia não foi gerado pela próxima autoridade na cadeia

CERTIFICATE_CHAIN_TOO_LONG Indicar que o tamanho da cadeia de servidores certificados excedeu o tamanho permitido pela política do emissor

EXPIRED Indicar que um certificado expirou

INAPPROPRIATE_KEY_USAGE Indicar que a chave pública do certificado foi usada de maneira considerada inapropriada pelo emissor

MISSING_SIGNATURE Indicar que um objeto certificado não contém uma assinatura

NOT_YET_VALID Indicar que um certificado ainda não é válido

ROOT_CA_EXPIRED Indicar que a chave pública da autoridade certificadora raiz (root CA) expirou

SITENAME_MISMATCH Indicar que um certificado não contém o nome correto do site

UNAUTHORIZED_INTERMEDIATE_CA Indicar que um certificado intermediário na cadeia não possui a permissão para ser uma autoridade certificadora intermediária

UNRECOGNIZED_ISSUER Indicar que um certificado foi emitido por uma entidade desconhecida

UNSUPPORTED_PUBLIC_KEY_TYPE Indicar que o tipo da chave pública no certificado não é suportado pelo dispositivo

UNSUPPORTED_SIGALG Indicar que um certificado foi assinado utilizando um algoritmo não suportado

VERIFICATION_FAILED Indicar uma verificação falha de certificado

Figura 4: Razões para uma exceção CertificateException

Desenvolvimento de Aplicações Móveis 9

Page 88: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

5. Sockets TCP

A maior parte das implementações de HTTP funcionam no topo da camada TCP. Ao enviar dados usando a camada TCP, estes podem ser divididos em pedaços menores chamado pacotes. A camada TCP garante que todos os pacotes enviados pelo transmissor serão recebidos pelo receptor na mesma ordem que eles foram enviados. Se um pacote não for recebido pelo receptor, ele será reenviado. Isso significa que quando uma mensagem é enviada, podemos ter certeza que ela será entregue para o receptor no mesmo formato na qual foi enviada, sem omissões ou inserções (exceto em circunstâncias extremas como o receptor sendo desconectado da rede).

A camada TCP é o responsável pela remontagem dos pacotes e retransmissão de forma transparente. Por exemplo, o protocolo HTTP não se preocupa com a montagem e desmontagem de pacotes porque isso deve ser tratados pela camada TCP.

Algumas vezes, o tamanho da mensagem é muito pequeno e torna-se muito ineficiente para ser enviado através de um único pacote (a sobrecarga do pacote é muito grande se comparada aos dados a serem enviado). Imagine muitos pacotes percorrendo a rede com apenas um byte de dados e muitos bytes de sobrecarga (digamos 16 bytes). Isso poderia fazer a rede ser muito ineficiente, muitos pacotes inundariam a rede com alguns poucos bytes de dados.

Nesses casos, a implementação do TCP deve aguardar mensagens subsequentes para serem enviadas. Então, poderá empacotar várias mensagens antes de enviar o pacote. Se isso ocorrer, poderá haver atraso ou latência na conexão. Se sua aplicação requer que a latência seja a menor possível, você deverá configurar a opção DELAY do socket para zero. Ou, se a aplicação pode conviver com perdas de pacotes ou pacotes desordenados, você pode querer testar uma conexão UDP ou Datagrama. Conexões UDP também possuem menos sobrecarga de pacotes.

5.1. Parte Cliente

Iremos na primeira parte do projeto construir as classes de comunicação do lado cliente para proceder à comunicação via sockets.

Classe ClientSocketMidlet.java:

package socket;import javax.microedition.midlet.*;import javax.microedition.lcdui.*;public class ClientSocketMidlet extends MIDlet { private static Display display; private boolean isPaused; public void startApp() { isPaused = false; display = Display.getDisplay(this); Client client = new Client(this); client.start(); } public static Display getDisplay() { return display; } public boolean isPaused() { return isPaused; } public void pauseApp() { isPaused = true; } public void destroyApp(boolean unconditional) { }}

Classe Client.java:

Desenvolvimento de Aplicações Móveis 10

Page 89: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

package socket;import java.io.*;import javax.microedition.io.*;import javax.microedition.lcdui.*;import javax.microedition.midlet.*;public class Client implements Runnable, CommandListener { private ClientSocketMidlet parent; private Display display; private Form f; private StringItem si; private TextField tf; private boolean stop; private Command sendCommand = new Command("Send", Command.ITEM, 1); private Command exitCommand = new Command("Exit", Command.EXIT, 1); InputStream is; OutputStream os; SocketConnection sc; Sender sender; public Client(ClientSocketMidlet m) { parent = m; display = Display.getDisplay(parent); f = new Form("Socket Client"); si = new StringItem("Status:", " "); tf = new TextField("Send:", "", 30, TextField.ANY); f.append(si); f.append(tf); f.addCommand(exitCommand); f.addCommand(sendCommand); f.setCommandListener(this); display.setCurrent(f); } public void start() { Thread t = new Thread(this); t.start(); } public void run() { try { sc = (SocketConnection) Connector.open("socket://localhost:5000"); si.setText("Connected to server"); is = sc.openInputStream(); os = sc.openOutputStream(); sender = new Sender(os); while (true) { StringBuffer sb = new StringBuffer(); int c = 0; while (((c = is.read()) != '\n') && (c != -1)) { sb.append((char) c); } if (c == -1) { break; } si.setText("Message received - " + sb.toString()); } stop(); si.setText("Connection closed"); f.removeCommand(sendCommand); } catch (ConnectionNotFoundException cnfe) { Alert a = new Alert("Client", "Please run Server MIDlet first", null, AlertType.ERROR); a.setTimeout(Alert.FOREVER); a.setCommandListener(this); display.setCurrent(a); } catch (IOException ioe) { if (!stop) {

Desenvolvimento de Aplicações Móveis 11

Page 90: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

ioe.printStackTrace(); } } catch (Exception e) { e.printStackTrace(); } } public void commandAction(Command c, Displayable s) { if ((c == sendCommand) && !parent.isPaused()) { sender.send(tf.getString()); } if ((c == Alert.DISMISS_COMMAND) || (c == exitCommand)) { parent.notifyDestroyed(); parent.destroyApp(true); } } public void stop() { try { stop = true; if (sender != null) { sender.stop(); } if (is != null) { is.close(); } if (os != null) { os.close(); } if (sc != null) { sc.close(); } } catch (IOException ioe) { } }}

Classe Sender.java:

package socket;import java.io.*;import javax.microedition.io.*;import javax.microedition.lcdui.*;import javax.microedition.midlet.*;public class Sender extends Thread { private OutputStream os; private String message; public Sender(OutputStream os) { this.os = os; start(); } public synchronized void send(String msg) { message = msg; notify(); } public synchronized void run() { while (true) { if (message == null) { try { wait(); } catch (InterruptedException e) { } } if (message == null) { break; }

Desenvolvimento de Aplicações Móveis 12

Page 91: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

try { os.write(message.getBytes()); os.write("\r\n".getBytes()); } catch (IOException ioe) { ioe.printStackTrace(); } message = null; } } public synchronized void stop() { message = null; notify(); }}

Desenvolvimento de Aplicações Móveis 13

Page 92: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

6. Server Sockets

No modelo cliente-servidor, o servidor continuamente espera pela conexão de um cliente que deverá conhecer o número da porta deste. Devemos utilizar o método Connector.open() para criar uma conexão do tipo socket. A URL passada para o método possui um formato semelhante ao um Socket TCP, com um hostname passado em branco (isto é, socket://:5000).

6.1. Parte Servidora

Iremos agora complementar as classes de comunicação via socket criando as classes que resolverão a parte do servidor.

Classe ServerSocketMidlet.java:

package socket;import javax.microedition.midlet.*;import javax.microedition.lcdui.*;public class ServerSocketMidlet extends MIDlet { private static Display display; private boolean isPaused; public void startApp() { isPaused = false; display = Display.getDisplay(this); Server server = new Server(this); server.start(); } public static Display getDisplay() { return display; } public boolean isPaused() { return isPaused; } public void pauseApp() { isPaused = true; } public void destroyApp(boolean unconditional) { }}

Classe Server.java:

package socket;import java.io.*;import javax.microedition.io.*;import javax.microedition.lcdui.*;import javax.microedition.midlet.*;public class Server implements Runnable, CommandListener { private ServerSocketMidlet parent; private Display display; private Form f; private StringItem si; private TextField tf; private boolean stop; private Command sendCommand = new Command("Send", Command.ITEM, 1); private Command exitCommand = new Command("Exit", Command.EXIT, 1); InputStream is; OutputStream os; SocketConnection sc; ServerSocketConnection scn; Sender sender;

Desenvolvimento de Aplicações Móveis 14

Page 93: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

public Server(ServerSocketMidlet m) { parent = m; display = Display.getDisplay(parent); f = new Form("Socket Server"); si = new StringItem("Status:", " "); tf = new TextField("Send:", "", 30, TextField.ANY); f.append(si); f.append(tf); f.addCommand(exitCommand); f.setCommandListener(this); display.setCurrent(f); } public void start() { Thread t = new Thread(this); t.start(); } public void run() { try { si.setText("Waiting for connection"); scn = (ServerSocketConnection) Connector.open("socket://:5000"); sc = (SocketConnection) scn.acceptAndOpen(); si.setText("Connection accepted"); is = sc.openInputStream(); os = sc.openOutputStream(); sender = new Sender(os); f.addCommand(sendCommand); while (true) { StringBuffer sb = new StringBuffer(); int c = 0; while (((c = is.read()) != '\n') && (c != -1)) { sb.append((char) c); } if (c == -1) { break; } si.setText("Message received - " + sb.toString()); } stop(); si.setText("Connection is closed"); f.removeCommand(sendCommand); } catch (IOException ioe) { if (ioe.getMessage().equals("ServerSocket Open")) { Alert a = new Alert("Server", "Port 5000 is already taken.", null, AlertType.ERROR); a.setTimeout(Alert.FOREVER); a.setCommandListener(this); display.setCurrent(a); } else { if (!stop) { ioe.printStackTrace(); } } } catch (Exception e) { e.printStackTrace(); } } public void commandAction(Command c, Displayable s) { if ((c == sendCommand) && !parent.isPaused()) { sender.send(tf.getString()); } if ((c == Alert.DISMISS_COMMAND) || (c == exitCommand)) { parent.notifyDestroyed(); parent.destroyApp(true); } } public void stop() {

Desenvolvimento de Aplicações Móveis 15

Page 94: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

try { stop = true; if (is != null) { is.close(); } if (os != null) { os.close(); } if (sc != null) { sc.close(); } if (scn != null) { scn.close(); } } catch (IOException ioe) { } }}

Desenvolvimento de Aplicações Móveis 16

Page 95: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

7. Datagramas

Conexões por soquetes TCP são seguras. Ao contrário, entregas de pacotes UDP não são garantidas. Não há garantias de que pacotes enviados utilizando conexões por datagramas sejam recebidas por quem as solicitou. A ordem em que os pacotes são recebidos não é segura. A ordem em que os pacotes são enviados não é a mesma ordem em que são recebidos.

Datagramas ou pacotes UDP são utilizados quando a aplicação pode se sustentar (continuar em operação) mesmo quando um pacote está perdido ou quando não são entregues em ordem.

7.1. Parte Servidora

Iniciaremos o projeto de comunicação por datagramas através da parte servidora.

Classe ServerDatagramMidlet.java:

package datagram;import javax.microedition.midlet.*;import javax.microedition.lcdui.*;public class ServerDatagramMidlet extends MIDlet { private static Display display; private boolean isPaused; public void startApp() { isPaused = false; display = Display.getDisplay(this); Server server = new Server(this); server.start(); } public static Display getDisplay() { return display; } public boolean isPaused() { return isPaused; } public void pauseApp() { isPaused = true; } public void destroyApp(boolean unconditional) { }}

Classe Server.java:

package datagram;import java.io.*;import javax.microedition.io.*;import javax.microedition.lcdui.*;import javax.microedition.midlet.*;public class Server implements Runnable, CommandListener { private ServerDatagramMidlet parent; private Display display; private Form f; private StringItem si; private TextField tf; private Command sendCommand = new Command("Send", Command.ITEM, 1); private Command exitCommand = new Command("Exit", Command.EXIT, 1); private Sender sender; private String address; public Server(ServerDatagramMidlet m) {

Desenvolvimento de Aplicações Móveis 17

Page 96: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

parent = m; display = Display.getDisplay(parent); f = new Form("Datagram Server"); si = new StringItem("Status:", " "); tf = new TextField("Send:", "", 30, TextField.ANY); f.append(si); f.append(tf); f.addCommand(sendCommand); f.addCommand(exitCommand); f.setCommandListener(this); display.setCurrent(f); } public void start() { Thread t = new Thread(this); t.start(); } public void run() { try { si.setText("Waiting for connection"); DatagramConnection dc = (DatagramConnection) Connector.open("datagram://:5555"); sender = new Sender(dc); while (true) { Datagram dg = dc.newDatagram(100); dc.receive(dg); address = dg.getAddress(); si.setText("Message received - " + new String(dg.getData(), 0, dg.getLength())); } } catch (IOException ioe) { Alert a = new Alert("Server", "Port 5000 is already taken.", null, AlertType.ERROR); a.setTimeout(Alert.FOREVER); a.setCommandListener(this); display.setCurrent(a); } catch (Exception e) { e.printStackTrace(); } } public void commandAction(Command c, Displayable s) { if ((c == sendCommand) && !parent.isPaused()) { if (address == null) { si.setText("No destination address"); } else { sender.send(address, tf.getString()); } } if ((c == Alert.DISMISS_COMMAND) || (c == exitCommand)) { parent.destroyApp(true); parent.notifyDestroyed(); } }}

7.2. Classe de Comunicação

Esta classe é aproveitada tanto pelo lado servidor quanto pelo lado cliente para o controle do envio das mensagens.

Classe Sender.java:

package datagram;import java.io.*;import javax.microedition.io.*;import javax.microedition.lcdui.*;

Desenvolvimento de Aplicações Móveis 18

Page 97: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

import javax.microedition.midlet.*;public class Sender extends Thread { private DatagramConnection dc; private String address; private String message; public Sender(DatagramConnection dc) { this.dc = dc; start(); } public synchronized void send(String addr, String msg) { address = addr; message = msg; notify(); } public synchronized void run() { while (true) { if (message == null) { try { wait(); } catch (InterruptedException e) { } } try { byte[] bytes = message.getBytes(); Datagram dg = null; if (address == null) { dg = dc.newDatagram(bytes, bytes.length); } else { dg = dc.newDatagram(bytes, bytes.length, address); } dc.send(dg); } catch (Exception ioe) { ioe.printStackTrace(); } message = null; } }}

7.3. Parte Cliente

Complementaremos o projeto com as classes que definem a parte cliente.

Classe ClientDatagramMidlet.java

package datagram;import javax.microedition.midlet.*;import javax.microedition.lcdui.*;public class ClientDatagramMidlet extends MIDlet { private static Display display; private boolean isPaused; public void startApp() { isPaused = false; display = Display.getDisplay(this); Client client = new Client(this); client.start(); } public static Display getDisplay() { return display; } public boolean isPaused() {

Desenvolvimento de Aplicações Móveis 19

Page 98: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

return isPaused; } public void pauseApp() { isPaused = true; } public void destroyApp(boolean unconditional) { }}

Classe Client.java:

package datagram;import java.io.*;import javax.microedition.io.*;import javax.microedition.lcdui.*;import javax.microedition.midlet.*;public class Client implements Runnable, CommandListener { private ClientDatagramMidlet parent; private Display display; private Form f; private StringItem si; private TextField tf; private Command sendCommand = new Command("Send", Command.ITEM, 1); private Command exitCommand = new Command("Exit", Command.EXIT, 1); private Sender sender; public Client(ClientDatagramMidlet m) { parent = m; display = Display.getDisplay(parent); f = new Form("Datagram Client"); si = new StringItem("Status:", " "); tf = new TextField("Send:", "", 30, TextField.ANY); f.append(si); f.append(tf); f.addCommand(sendCommand); f.addCommand(exitCommand); f.setCommandListener(this); display.setCurrent(f); } public void start() { Thread t = new Thread(this); t.start(); } public void run() { try { DatagramConnection dc = (DatagramConnection) Connector.open( "datagram://localhost:5555"); si.setText("Connected to server"); sender = new Sender(dc); while (true) { Datagram dg = dc.newDatagram(100); dc.receive(dg); if (dg.getLength() > 0) { si.setText("Message received - " + new String(dg.getData(), 0, dg.getLength())); } } } catch (ConnectionNotFoundException cnfe) { Alert a = new Alert("Client", "Please run Server MIDlet first", null, AlertType.ERROR); a.setTimeout(Alert.FOREVER); display.setCurrent(a); } catch (IOException ioe) { ioe.printStackTrace();

Desenvolvimento de Aplicações Móveis 20

Page 99: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

} } public void commandAction(Command c, Displayable s) { if ((c == sendCommand) && !parent.isPaused()) { sender.send(null, tf.getString()); } if (c == exitCommand) { parent.destroyApp(true); parent.notifyDestroyed(); } }}

Desenvolvimento de Aplicações Móveis 21

Page 100: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

8. Exercícios

8.1. Buscar dados da URL

Criar um MIDlet que detalhe um endereço HTTP. Pesquisar a URL utilizando o método GET e mostrar as propriedades desta conexão (caso esteja disponível), tais como: código da resposta, descrição da mensagem, tamanho, tipo, modo de codificação, se está finalizado e data da última modificação.

Desenvolvimento de Aplicações Móveis 22

Page 101: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

Módulo 5Desenvolvimento de Aplicações Móveis

Lição 7Comunicação Corporativa

Versão 1.0 - Set/2007

Page 102: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

AutorA. Oliver de Guzman

EquipeRommel FeriaJohn Paul Petines

Necessidades para os ExercíciosSistemas Operacionais SuportadosNetBeans IDE 5.5 para os seguintes sistemas operacionais:

• Microsoft Windows XP Profissional SP2 ou superior• Mac OS X 10.4.5 ou superior• Red Hat Fedora Core 3 • Solaris™ 10 Operating System (SPARC® e x86/x64 Platform Edition)

NetBeans Enterprise Pack, poderá ser executado nas seguintes plataformas:• Microsoft Windows 2000 Profissional SP4• Solaris™ 8 OS (SPARC e x86/x64 Platform Edition) e Solaris 9 OS (SPARC e

x86/x64 Platform Edition) • Várias outras distribuições Linux

Configuração Mínima de HardwareNota: IDE NetBeans com resolução de tela em 1024x768 pixel

Sistema Operacional Processador Memória HD Livre

Microsoft Windows 500 MHz Intel Pentium III workstation ou equivalente

512 MB 850 MB

Linux 500 MHz Intel Pentium III workstation ou equivalente

512 MB 450 MB

Solaris OS (SPARC) UltraSPARC II 450 MHz 512 MB 450 MB

Solaris OS (x86/x64 Platform Edition)

AMD Opteron 100 Série 1.8 GHz 512 MB 450 MB

Mac OS X PowerPC G4 512 MB 450 MB

Configuração Recomendada de Hardware

Sistema Operacional Processador Memória HD Livre

Microsoft Windows 1.4 GHz Intel Pentium III workstation ou equivalente

1 GB 1 GB

Linux 1.4 GHz Intel Pentium III workstation ou equivalente

1 GB 850 MB

Solaris OS (SPARC) UltraSPARC IIIi 1 GHz 1 GB 850 MB

Solaris OS (x86/x64 Platform Edition)

AMD Opteron 100 Series 1.8 GHz 1 GB 850 MB

Mac OS X PowerPC G5 1 GB 850 MB

Requerimentos de SoftwareNetBeans Enterprise Pack 5.5 executando sobre Java 2 Platform Standard Edition Development Kit 5.0 ou superior (JDK 5.0, versão 1.5.0_01 ou superior), contemplando a Java Runtime Environment, ferramentas de desenvolvimento para compilar, depurar, e executar aplicações escritas em linguagem Java. Sun Java System Application Server Platform Edition 9.

• Para Solaris, Windows, e Linux, os arquivos da JDK podem ser obtidos para sua plataforma em http://java.sun.com/j2se/1.5.0/download.html

• Para Mac OS X, Java 2 Plataform Standard Edition (J2SE) 5.0 Release 4, pode ser obtida diretamente da Apple's Developer Connection, no endereço: http://developer.apple.com/java (é necessário registrar o download da JDK).

Para mais informações: http://www.netbeans.org/community/releases/55/relnotes.html

Desenvolvimento de Aplicações Móveis 2

Page 103: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

Colaboradores que auxiliaram no processo de tradução e revisãoAécio JúniorAlexandre MoriAlexis da Rocha SilvaAllan Souza NunesAllan Wojcik da SilvaAnderson Moreira PaivaAndre Neves de AmorimAngelo de OliveiraAntonio Jose R. Alves RamosAurélio Soares NetoBruno da Silva BonfimCarlos Fernando GonçalvesDenis Mitsuo Nakasaki

Fábio BombonatoFabrício Ribeiro BrigagãoFrancisco das ChagasFrederico DubielHerivelto Gabriel dos SantosJacqueline Susann BarbosaJoão Vianney Barrozo CostaKefreen Ryenz Batista LacerdaKleberth Bezerra G. dos SantosLeandro Silva de MoraisLeonardo Ribas SegalaLucas Vinícius Bibiano ThoméLuciana Rocha de Oliveira

Luiz Fernandes de Oliveira Junior Marco Aurélio Martins BessaMaria Carolina Ferreira da SilvaMassimiliano GiroldiMauro Cardoso MortoniPaulo Afonso CorrêaPaulo Oliveira Sampaio ReisPedro Henrique Pereira de AndradeRonie DotzlawSeire ParejaSergio TerzellaVanessa dos Santos AlmeidaRobson Alves Macêdo

Auxiliadores especiais

Revisão Geral do texto para os seguintes Países:

• Brasil – Tiago Flach• Guiné Bissau – Alfredo Cá, Bunene Sisse e Buon Olossato Quebi – ONG Asas de Socorro

Coordenação do DFJUG

• Daniel deOliveira – JUGLeader responsável pelos acordos de parcerias• Luci Campos - Idealizadora do DFJUG responsável pelo apoio social• Fernando Anselmo - Coordenador responsável pelo processo de tradução e revisão,

disponibilização dos materiais e inserção de novos módulos• Rodrigo Nunes - Coordenador responsável pela parte multimídia• Sérgio Gomes Veloso - Coordenador responsável pelo ambiente JEDITM (Moodle)

Agradecimento Especial

John Paul Petines – Criador da Iniciativa JEDITM

Rommel Feria – Criador da Iniciativa JEDITM

Desenvolvimento de Aplicações Móveis 3

Page 104: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

1. Objetivos

Nesta lição, aprenderemos a escrever Servlets, utilizar páginas com JSP e JSTL, acessar um banco de dados através de JDBC e a criar e ler documentos XML.

Ao final desta lição, o estudante será capaz de:

• Escrever Servlets simples• Escrever Java Server Pages (JSP) simples utilizando JSTL • Escrever código JSTL utilizando Expression Language (EL)• Acessar banco de dados utilizando a tecnologia JDBC• Gerar XML• Ler um arquivo XML no cliente móvel

Desenvolvimento de Aplicações Móveis 4

Page 105: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

2. Servlets

Servlet é uma classe Java que é executada no servidor WEB para implementar transações do tipo requisição-resposta (request-response). Através dos servlet, a tecnologia Java fornece uma alternativa melhor e mais portável do que scripts CGI (Common Gateway Interface). Comparado com scripts CGI (escritos em Perl, scripts sheel, ou outras linguagens de script), servlet fornece uma tecnologia escalável, independente de plataforma, para entregar conteúdo dinâmico.

Um servlet tem dois métodos para processar uma requisição, os métodos doGet() e doPost(). Esses métodos são chamados quando um cliente WEB (browser) envia um comando "GET" ou "POST". Esses métodos têm parâmetros idênticos. Esses parâmetros são normalmente entregues para um método comum. Portanto, tanto a requisição GET quanto a requisição POST são manipuladas da mesma maneira.

protected void doGet( HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // requisição de processamento ...}protected void doPost( HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // requisição de processamento ...}

A seguir teremos um servlet completo:

import java.io.*;import java.net.*;import javax.servlet.*;import javax.servlet.http.*;public class SampleServlet extends HttpServlet { protected void processRequest( HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); out.println("<html>"); out.println("<head>"); out.println("<title>Servlet SampleServlet</title>"); out.println("</head>"); out.println("<body>"); out.println("<h1>Servlet SampleServlet at " + request.getContextPath () + "</h1>"); out.println("</body>"); out.println("</html>"); out.close(); } protected void doGet( HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } protected void doPost( HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } /** Retorna uma breve descrição do servlet. */

Desenvolvimento de Aplicações Móveis 5

Page 106: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

public String getServletInfo() { return "Short description"; }}

Para criar um novo Projeto WEB (Web Project) no NetBeans, selecione a partir do menu principal a opção File -> New Project...

Figura 1: Janela New Project do NetBeans

Na janela acima selecione em Categories a opção Web e em Projects selecione a opção Web Application.

Desenvolvimento de Aplicações Móveis 6

Page 107: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

Figura 2: Janela New Web Application do NetBeans

Na janela acima informe o nome para o projeto e pressione o botão Finish. Após o projeto criado poderemos criar um novo arquivo tipo servlet. Para o mesmo. Para criar este arquivo selecione, a partir do menu principal, a opção em File -> New File...

Figura 3: Janela New File do NetBeans

Na janela acima selecione em Categories a opção Web e em File Types selecione a opção Servlet.

Figura 4: Janela New Servlet do NetBeans

Na janela acima informe o nome para o servlet e pressione o botão Finish.

Desenvolvimento de Aplicações Móveis 7

Page 108: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

3. JSP e JSTL

O objetivo primário das Java Server Pages (JSP) e Standard Tag Library (JSTL) é ajudar aos desenvolvedores simplificar a escrita das de páginas WEB. JSTL faz a ponte entre programadores e autores (não programadores) fornecendo uma linguagem de expressão simples para a construção de páginas JSP.

Além do suporte às ações da linguagem de expressão e de fluxo de controle, JSTL fornece também funcionalidade para acessar recursos baseados em URL, internacionalização e formatação de números e datas, acesso de base de dados e processamento de XML.

JTSL é composta de diversas bibliotecas de tags, agrupadas com base na área funcional.

Área Prefixo URI Exemplo de código

core c http://java.sun.com/jstl/core <c:out value="${var}"/>

I18N formatting fmt http://java.sun.com/jstl/fmt <fmt:formatNumber

XML processing x http://java.sun.com/jstl/xml <x:forEach ...

Database (SQL) sql http://java.sun.com/jstl/sql <sql:query var=...

Functions fn http://java.sun.com/jstl/functions <fn:

Nesta seção, abordaremos o uso da biblioteca core.

3.1. Configuração

Para usar as tags JSTL, a diretiva da taglib deve ser incluída na página JSP, uma para cada área funcional que será usada na página.

<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %>

Figura 5: Código JSP com a tag core

Deve-se incluir também o jstl.jar no diretório de bibliotecas do projeto:

1. Pressionar o botão direito do mouse em cima do diretório de bibliotecas do projeto e selecionar "Add Library" no menu pop-up:

Figura 6: Adicionando uma biblioteca ao projeto

Desenvolvimento de Aplicações Móveis 8

Page 109: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

2. Selecionar "JSTL 1.1" e selecionar a opção "Add Library". "JSTL 1.1 – standard.jar" e "STL 1.1 – jstl.jar" serão adicionados à biblioteca do projeto.

Figura 7: Adicionando uma biblioteca ao projeto

3.2. Hello, world!

Uma página JSP, ao contrário de um servlet, é uma página HTML com tags que permitem a programação Java. A seguir temos uma página JSP:

<%@page contentType="text/html"%><%@page pageEncoding="UTF-8"%><%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><c:set var="mensagem" value="hello, world!"/><html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title><c:out value="${mensagem}"/></title> </head> <body> <h1><c:out value="${mensagem}"/></h1> </body></html>

Seguindo as mesmas instruções para gerar um servlet, entretanto selecione JSP e indique o nome como hello.jsp. Para ver a saída desta página, pressionar o botão direito do mouse em cima do nome do arquivo e selecionar a opção "Run File" é mostrado o seguinte resultado no seu navegador web:

Figura 8: Resultado da execução da página JSP

Desenvolvimento de Aplicações Móveis 9

Page 110: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

3.3. Transferindo controle do Servlet para JSP

import java.io.*;import java.net.*;import javax.servlet.*;import javax.servlet.http.*;public class SampleServlet2 extends HttpServlet { protected void processRequest( HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String[] days = {"Sunday", "Monday", "Tuesday", "Wednesday"}; request.setAttribute("days", days); request.setAttribute("message", "hello, world!"); // Transfere o controle para a página JSP RequestDispatcher dispatcher = request.

getRequestDispatcher("/hello.jsp"); if (dispatcher != null) dispatcher.forward(request, response); } protected void doGet( HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } protected void doPost( HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } public String getServletInfo() { return "Short description"; }}

Figura 9: Resultado da execução do Servlet

Desenvolvimento de Aplicações Móveis 10

Page 111: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

3.4. Linguagem de Expressão

3.4.1. Acessando Atributos, Propriedades e Coleções

Para acessar um atributo, a sintaxe é: ${var}Exemplo: saída do valor do atributo username

<c:out value="${username}"/>

JSTL unifica o acesso às propriedades do JavaBean e valores de coleção. A expressão varX.varY é equivalente para varX[varY] em JSTL. A expressão varX.varY (ou varX[varY]) será avaliada, dependendo do tipo de varX:

1. Se varX é um JavaBean, varY será convertido em cadeia de caractere. Se varY é uma propriedade de leitura de varX, ela pode retornar o resultado da chamada ao método de acesso: varX.getVarY()

2. Se varX é uma coleção do tipo List: varY é forçada para int. Converter para: varX.get(varY)

3. Se varX é uma coleção do tipo Vector: varY é forçada para int. Converter para: Array.get(varX, varY)

4. Se varX é uma coleção do tipo Map: Converter para: varX.get(varY)

Os atributos podem ter escopo de página, de requisição e da aplicação. O linguagem de expressão procuraria pelo identificador nestes escopos. Se o identificador não for achado, é retornado nulo.

3.4.2. Objetos Implícitos

JSTL inicializa automaticamente diversos atributos de mapeamento com valores de origens diferentes. Estes atributos estão disponíveis para as páginas JSP sem qualquer inicialização do usuário. Por exemplo, o atributo “param” contém mapeamentos de nomes de parâmetros e valores de requisição. Estes nomes e valores (param) vêm de formulários HTML, através da de submissão de métodos HTTP GET ou POST.

Objeto Implícito

Conteúdo

pageScope Contém um mapeamento de nomes de atributos de escopo de página para seus valores

requestScope Contém um mapeamento de nomes de atributos de escopo de requisição para seus valores

sessionScope Contém um mapeamento de nomes de atributos de escopo de sessão para seus valores

applicationScope Contém um mapeamento de nomes de atributos de escopo de aplicação para seus valores

param Contém um mapeamento de nomes de parâmetros para seus valores de parâmetros (cadeia de caracteres). Equivalente a ServletRequest.getParameter(String)

header Contém um mapeamento de nomes de cabeçalho para seus valores (cadeia de caracteres). Equivalente a servletRequst.getHeader(String)

cookie Contém contendo um mapeamento de nomes de "cookies" para seus valores. Equivalente a HttpServletRequest.getCookie(String)

3.4.3. Operadores

A linguagem da expressão (EL) da JSTL suporta operadores relacionais, aritméticos e lógicos. Os operadores relacionais suportados são:

● == ou eq● != ou ne● < ou lt

Desenvolvimento de Aplicações Móveis 11

Page 112: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

● > ou gt● <= ou le● >= ou ge

Os operadores lógicos suportados são:

● && ou and● || ou or● ! ou not

E os operadores aritméticos suportados são:

● + (adição)● - (subtração)● * (multiplicação)● / (divisão)● % ou mod (resto da divisão ou módulo)

O operador adicional empty é muito útil para testar valores nulos ou vazios.

<c:if test="${empty param.username}">No username</c:if>

3.4.4. Exceções a Valores Padrões (Básicos)

Para simplificar páginas de JSP, os erros simples não gerarão exceções. Indicar um atributo com um valor nulo indicará simplesmente “(zero)” em vez de gerar um NullPointerException.

Username: <inputtype="text" value="<c:out value="${param.username}"/>"name="username" />

Qualquer atributo não definido que for utilizado em expressões terá seu valor padrão como 0 (zero). Esta expressão retornaria o valor 1, se o parâmetro “start” não fosse inicializado:

<c:out value="${param.start + 1}"/>

3.5. Biblioteca Core

3.5.1. Tag <c:out>

O tag <c:out> avalia uma expressão e retorna o seu resultado.

Sintaxe :

<c:out value="value" [escapeXml="{true|false}"] [default="defaultValue"]/>

Nome Dinâmico Requisito Tipo Descrição

value sim sim Objeto A expressão a ser avaliada

escapeXml sim não boolean

Se verdadeiro, os caracteres <, >, &, ' e " são convertidos em seus códigos da entidade do caráter (por exemplo: > conversos ao &gt;). O valor padrão é true.

default sim não Objeto O valor padrão se o valor do resultado for nulo

Exemplos:

Desenvolvimento de Aplicações Móveis 12

Page 113: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

Rows: <c:out value="${param.numRows}" defaultValue="20" />Description:<pre> <c:out value="${bookmark.description}" escapeXml="false" /></pre>

3.5.2. Tag <c:set>

Ajusta o valor de um atributo em um determinado escopo.

Sintaxe:

<c:set value="value" var="varName" [scope="{page|request|session|application}"]/>

Nome Dinâmico Requisito Tipo Descriçãovalue sim sim Objeto A expressão a ser avaliada

var não sim StringO nome do atributo exportada que conterá o valor da expressão. O tipo do atributo segue o tipo do resultado da expressão

scope não não String O escopo do atributo

Exemplo:

<c:set var="fullName" value="${lastName, firstName}" />

3.5.3. Tag <c:remove>

Esta tag remove um atributo de um determinado escopo.

Sintaxe:

<c:remove var="varName" [scope="{page|request|session|application}"]/>

Nome Dinâmico Requisito Tipo Descriçãovar não sim String O nome do atributo a ser eliminado

scope não não String O escopo do atributo

3.5.4. Tag <c:if>

Realiza uma avaliação condicional. O conteúdo do corpo será processado se o teste de avaliação da condição informada for verdadeiro.

Sintaxe:

<c:if test="testCondition" [var="varName"] [scope="{page|request|session|application}"]> body content</c:if>

ou

<c:if test="testCondition" var="varName" [scope="{page|request|session|application}"]/>

Desenvolvimento de Aplicações Móveis 13

Page 114: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

Nome Dinâmico Requerido Tipo Descrição

test sim sim boolean A condição testada que determina se o conteúdo do corpo deverá ser processado

var não não/sim StringNome do atributo exportado que irá conter o valor da condição testada. O tipo do atributo de escopo é Boolean

scope não não String Escopo do atributo

Exemplo:

<c:if test="${empty param.username}">No username</c:if>

3.5.5. Tag <c:choose><c:when><c:otherwise>

A tag <c:choose> é uma substituta para a instrução if-else-if do Java, permitindo a execução condicional mutuamente exclusiva. O conteúdo do corpo composto pela tag <c:otherwise> será avaliado se nenhuma instrução das tags <c:when> for considerada verdadeira. O bloco <c:otherwise> deverá ser o último da instrução e também ser precedido por no mínimo uma tag do tipo <c:when>.

Sintaxe:

<c:choose> <c:when test="condition1"> instruções para esta condição </c:when> <c:when test="condition2"> instruções para esta condição </c:when>... <c:otherwise> instruções caso nenhuma condição tenha sido considerada verdadeira </c:otherwise></c:choose>

Nome Dinâmico Requerido Tipo Descrição

test sim sim boolean A condição de teste que determina se o conteúdo do corpo deverá ser processado

Exemplo:

<c:choose> <c:when test="${gender eq 'M'}">Male</c:when> <c:when test="${gender eq 'F'}">Female</c:when> <c:otherwise>Unknown</c:otherwise></c:choose>

3.5.6. Tag <c:forEach>

A tag <c:forEach> realiza iteração sobre o conteúdo de uma coleção. A coleção pode ser qualquer uma das subclasses de java.util.Collection e java.util.Map. Arrays de objetos e tipos primitivos também são suportados. Uma String com valores separados por vírgula ("True,False") também pode ser utilizada para o processo. Enquanto houver itens na coleção o conteúdo do corpo será processado.

A tag também poderá ser utilizada para iterações com número fixo de repetições.

O atributo varStatus é do tipo javax.servlet.jsp.jstl.core.LoopTagStatus e tem a propriedade index (índice da iteração atual, iniciado em zero) e count (a contagem da iteração atual, iniciada em 1 (um), por exemplo, se o índice inicial é 20, o índice final é 80 e o intervalo é 10, o count poderá ser 1,2,3,4,5,6,7). As propriedades lógicas first e last indicam se a iteração atual é a primeira ou a última, respectivamente. Existem também as propriedades begin, end e step que guardam os

Desenvolvimento de Aplicações Móveis 14

Page 115: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

valores dos argumentos inicial, final e do passo realizado pelo laço.

Sintaxe:

<c:forEach [var="varName"] items="collection" [varStatus="varStatusName"] [begin="begin"] [end="end"] [step="step"]> instruções a serem executadas</c:forEach>

ou

<c:forEach [var="varName"] [varStatus="varStatusName"] begin="begin" end="end" [step="step"]> instruções a serem executadas</c:forEach>

Nome Dinâmico Requerido Tipo Descrição

var não não variável O nome de um atributo exportado para cada elemento de uma coleção

items sim sim/nãoCollection, Map, Array, String

Coleção de itens para realizar interações

varStatus não não StringO nome do atributo exportado para a situação da operação. O tipo do objeto exportado é javax.servlet.jsp.jstl.core.LoopTagStatus

begin sim não/sim int Índice inicial (base zero) na coleção, ou um índice inicial fixo (se a coleção não for especificada)

end sim não/sim int Índice final (base zero) na coleção, ou um índice final fixo (se a coleção não for especificada)

step sim não int O laço será processado por um intervalo definido de itens da iteração

Exemplo:

<select name="gender"><c:forEach var="gender" items="${genderList}"> <option value="<c:out value="${gender.code}"/>"> <c:out value="${gender.name}"/> </option></c:forEach></table>

3.5.7. Tag <c:forTokens>

Esta tag realiza iteração sobre os segmentos de texto que devem ser separados por um delimitador em um objeto do tipo String.

Sintaxe:

<c:forTokens items="stringOfTokens" delims="delimiters" [var="varName"] [varStatus="varStatusName"] [begin="begin"] [end="end"] [step="step"]> instruções a serem executadas

Desenvolvimento de Aplicações Móveis 15

Page 116: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

</c:forTokens >

Nome Dinâmico Requerido Tipo Descrição

var não não String O nome do atributo exportado para toda instrução iteração e símbolo

items sim sim String Literal de símbolos

delims sim sim String Delimitadores, caracteres que separam os símbolos no literal de itens

varStatus não não StringO nome do atributo exportado para o status da operação. O objeto exportado é do tipo javax.servlet.jsp.jstl.core.LoopTagStatus

begin sim não intÍndice do começo (base-zero) da iteração. Se não for especificado, a iteração vai começar com o primeiro símbolo.

end sim não int Final do índice da iteração

step sim não int O laço será processado por um intervalo definido de itens da iteração

Exemplo:

<select name="gender"><c:forEach var="gender" items="Male,Female" delims=","> <option value="<c:out value="${gender}"/>"> <c:out value="${gender}"/> </option></c:forEach></table>

Desenvolvimento de Aplicações Móveis 16

Page 117: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

4. JDBC

Nessa seção, discutiremos como persistir dados ou objetos. Para essa funcionalidade precisamos de um banco de dados (relacional). A biblioteca JDBC permite executar consultas e alterações em um banco de dados. Antes de podermos usar o JDBC, precisamos ter certeza de que três pré-requisitos estão sendo satisfeitos:

● JDBC library (biblioteca) – incluído no JDK

● O servidor de banco de dados – usaremos o MySQL (www.mysql.com)

● Driver JDBC – vem com o DBMS, instale o jar mysql-connector-java-3.x.x-bin.jar para o JDBC 3.0

Figura 10: Adicionando as bibliotecas ao projeto

A tabela usada nesses exemplos pode ser recriada usando os comandos SQL CREATE AND INSERT:

CREATE TABLE `task` ( `id` bigint(20) unsigned NOT NULL auto_increment, `task` varchar(128) NOT NULL default '', `duration` int(11) NOT NULL default '0', `assignedTo` varchar(64) NOT NULL default '', `status` char(1) NOT NULL default '', PRIMARY KEY (`id`));INSERT INTO `task` (`id`, `task`, `duration`, `assignedTo`, `status`)VALUES (1,'connect to database',2,'alex','0'),(2,'list table rows',4,'alex','0'),(3,'update row',8,'you','0');

4.1. Carregando o Driver

Para utilizar o driver JDBC com um banco de dados em particular temos que carregá-lo utilizando Class.forName(). O nome do driver é dependente do driver do banco de dados que carregaremos. Em nosso caso, utilizaremos o mysql jdbc driver:

String driver = "com.mysql.jdbc.Driver";Class.forName(driver);

4.2. Estabelecendo a Conexão

Para estabelecer uma conexão com o banco de dados precisamos da URL para o banco de dados. Precisaremos também ter acesso ao banco de dados. Um nome de usuário e senha válidos para o acesso ao banco de dados serão requeridos.

String url = "jdbc:mysql://localhost:3306/jedi";String username = "root";

Desenvolvimento de Aplicações Móveis 17

Page 118: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

String password = "password";conn = DriverManager.getConnection(url, username, password);

4.3. Executando consultas SQL

O método executeQuery() retorna um objeto do tipo ResultSet. Para percorrer por todas as linhas do resultado da consulta utilizaremos o método next(). Existem alguns métodos que retornam as colunas da linha corrente, cada uma para um tipo de dados específico. Nesse exemplo, recuperamos atributos dos tipos String e int utilizando getString() e getInt():

Statement statement = conn.createStatement();String query = "SELECT task,duration,duration FROM task";ResultSet rs = statement.executeQuery(query);out.println("<table>");out.println("<tr>");out.println("<th>Task</th>");out.println("<th>Duration</th>");out.println("<th>Assigned to</th>");out.println("</tr>");while (rs.next()) { String task = rs.getString("task"); int duration = rs.getInt("duration"); String assignedTo = rs.getString("assignedTo"); out.println("<tr>"); out.println("<td>" + task + "</td>"); out.println("<td>" + duration + "</td>"); out.println("<td>" + duration + "</td>"); out.println("</tr>");}out.println("</table>");

Figura 11: Resultado da consulta

4.4. Alterando tabelas

Para modificar registros nas tabelas com os comandos INSERT, UPDATE e DELETE (inclusão, alteração e exclusão, respectivamente), o método executeUpdate() é utlizado.

String task = (String) request.getParameter("task");String duration = (String) request.getParameter("duration");String assignedTo = (String) request.getParameter("assignedTo");String status = (String) request.getParameter("status");Long id = new Long(idStr);String updateQuery;ResultSet rs = dao.query("SELECT id from task WHERE id ='" + id + "'");if (rs.next()){ // altera a entrada da tarefa updateQuery = "UPDATE task SET" + " task='" + (task != null? task:"") + "'" + ",duration='" + (duration != null ? duration:"") + "'" + ",assignedTo='" + (assignedTo != null ? assignedTo:"") + "'" + ",status='" + (status != null ? status:"") + "'" + " WHERE id=" + id;} else { // nova entrada da tarefa updateQuery = "INSERT INTO task (task, duration, assignedTo, status) " + "VALUES ("

Desenvolvimento de Aplicações Móveis 18

Page 119: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

+ "'" + task + "'," + "'" + duration + "'," + "'" + assignedTo + "'," + "'" + status + "'" + ")";}statement.executeUpdate(updateQuery);

Desenvolvimento de Aplicações Móveis 19

Page 120: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

5. XML

XML, a linguagem de marcação extensível (eXtensible Markup Language), é uma linguagem de marcação baseada em texto. Com XML, pode-se apresentar dados em um documento estruturado de texto.

Assim como o HTML, as tags XML são definidas usando os símbolos maior e menor: <>. Entretanto, diferente do HTML, XML é mais fácil de se analisar. Um documento XML é estruturado com entidades formando uma estrutura de árvore.

Pode-se utilizar qualquer nome de tag apropriado que seja desejado, desde que todas as aplicações que utilizam o documento XML utilizem os mesmos nomes de tag. Tags podem conter atributos. No exemplo abaixo, a primeira "task" (tarefa) tem um atributo "id" (identificador) igual a "1" enquanto a segunda "task" tem um atributo "id" igual a "2".

<tasks> <task id="1"> <name>connect to database</name> <duration>2</duration> <assignedTo>alex</assignedTo> <status>0</status> </task> <task id="2"> <name>list table rows</name> <duration>4</duration> <assignedTo>alex</assignedTo> <status>4</status> </task></tasks>

5.1. Analisando o XML

Até a data da escrita deste texto, não havia nenhuma biblioteca padrão definida pelo JCP para análise de XML em CLDC. Entretanto, existem muitas bibliotecas XML que trabalham com a CLDC. Uma delas é a NanoXML (http://nanoxml.sourceforge.net/). A versão original da NanoXML não trabalha com a CLDC. O usuário deve baixar a versão modificada que trabalha com CLDC em http://www.ericgiguere.com/nanoxml e incluí-la no seu projeto móvel sob o nome de pacote "nanoxml".

import java.io.*;import java.util.*;import nanoxml.*;... public String[] parseXml(String xml) { kXMLElement root = new kXMLElement(); try { root.parseString(xml); Vector taskList = root.getChildren(); Vector items = new Vector(); for (int i=0; i<taskList.size(); i++){ kXMLElement task = (kXMLElement) taskList.elementAt(i); String tagName = task.getTagName(); if (tagName != null && tagName.equalsIgnoreCase("task")){ Vector taskProperties = task.getChildren(); String[] fieldNames = {"name", "duration", "assignedTo", "status"}; String[] fields = new String[fieldNames.length]; String id = task.getProperty("id", "0"); for (int j=0; j<taskProperties.size(); j++) { kXMLElement prop = (kXMLElement) taskProperties.elementAt(j); String propTagName = prop.getTagName(); if (propTagName != null) { for (int p=0; p<fieldNames.length; p++) { if (propTagName.equalsIgnoreCase(fieldNames[p])) {

Desenvolvimento de Aplicações Móveis 20

Page 121: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

fields[p] = prop.getContents(); } } } } items.addElement(id + ": " + fields[0]); } } String[] itemArr = new String[items.size()]; items.copyInto(itemArr); return itemArr; } catch( kXMLParseException ke ){ return(null); } }

Desenvolvimento de Aplicações Móveis 21

Page 122: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

6. Exercícios

6.1. Cabeçalhos das tabelas com linhas de cores alternadas

Escrever um código JSTL que irá interagir com o mapa implícito "header" e mostrar o header chave/nome e o valor em uma tabela HTML. Linhas de número ímpar tem um fundo na cor lightyellow (<tr bgcolor="lightyellow">...). Note que o índice varStatus começa em zero. Note que o (header) Map tem as propriedades "key" e "value".

Saída do exemplo:

accept-encoding gzip,deflate

connection keep-alive

accept-language en-us,en;q=0.5

host localhost:8084

accept-charset ISO-8859-1,utf-8;q=0.7,*;q=0.7

user-agent Mozilla/5.0 (Linux; U; Linux v0.99; en-US) Gecko/20050511 Firefox/1.2.3

accept text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5

keep-alive 300

6.2. Servlets e JSP

Criar um servlet e uma aplicação JSTL que deve mostrar no formato XML em um array de objetos. Os atributos do objeto são: nome e endereço IP. A classe Java deve parecer com esta:

public class Host { private String name; private String ip; public Host(String name, String ip) { this.name = name; this.ip = ip; } public String getName(){ return(name); } public String getIp(){ return(ip); } public void setName(String name){ this.name = name; } public void setIp(String ip){ this.ip = ip; } }

Deve se passar um array estático dos Hosts no Servlet para o JSP usando o método request.setAttribute().

Host[] hosts = { new Host("localhost", "127.0.0.1"), new Host("java.sun.com", "1.2.3.4")};

A saída em XML se deve parecer como esta:

<hosts> <host name="localhost"> <ip>127.0.0.1</ip> </host> <host name="java.sun.com"> <ip>1.2.3.4</ip> </host></hosts>

Desenvolvimento de Aplicações Móveis 22

Page 123: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

Módulo 5Desenvolvimento de Aplicações Móveis

Lição 8Otimizações

Versão 1.0 - Set/2007

Page 124: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

1. Objetivos

Antes de realmente fazer qualquer otimização em seus programas, deve-se certificar de que o pacote de software é de boa qualidade. A execução das otimizações nas classes do projeto deve ser deixado por último. Algumas técnicas discutidas nesta lição são úteis para evitar alguns erros de programação.

Ao final desta lição, o estudante será capaz de:

• Utilizar as diferentes técnicas de otimização em aplicações móveis.

Desenvolvimento de Aplicações Móveis 4

Page 125: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

2. Execução de Classes

2.1. Utilizar StringBuffer ao invés de String

Deve-se recordar que em Java Strings são objetos imutáveis. Usando-se os métodos de String criamos objetos individuais da String. A simples concatenação de Strings cria múltiplos objetos de Strings (a menos que as Strings sejam constantes e o compilador seja aguçado o suficiente para concatená-las durante sua compilação). O uso da StringBuffer não apenas otimiza o tempo de execução de suas classes (menos tempo de execução na criação de objetos), como também irá otimizar o uso da memória (menos Strings para alocar).

String StringBuffer

String a, b, c;...String message = "a=" + a + "\n" + "b=" + b + "\n" + "c=" + c + "\n";

String a, b, c;...StringBuffer message = new StringBuffer(255);message.append("a=");message.append(a);message.append("\n");message.append("b=");message.append(b);message.append("\n");message.append("c=");message.append(c);message.append("\n");

2.2. Utilizar uma área de clipping ao desenhar

Usar Graphics.setClip() reduz o tempo de execução porque se está desenhando, somente, o número correto de pixels na tela. Lembre-se que gráficos desenhados na tela consomem muito tempo de execução. Reduzir o número de pixels a serem desenhados melhora o desempenho de seu programa durante a execução.

Graphics g;int x1, y1, x2, y2;...g.setClip(x1, y1, x2, y2);g.drawString("JEDI", x, y, Graphics.TOP | Graphics.HCENTER);// mais operações com desenhos...

2.3. Evitar o modificador sincronizado

Usar um modificador do tipo sincronizado aumentará a velocidade de execução de sua classe, pois ao mesmo tempo que ele terá de executar algumas medidas extras e não poderá ser acessado simultaneamente.

2.4. Passar o menor número de parâmetros possível

Ao chamar um método, o interpretador empurra todos os parâmetros para a pilha da execução. Passar muitos parâmetros afeta a velocidade de execução e utiliza muita memória.

2.5. Reduzir as chamadas de métodos

As chamadas de métodos ocupam muita memória e tempo de execução. Veja o item anterior.

2.6. Atrasar as inicializações

Para ganhar tempo no início das aplicações, atrase todas as inicializações pesadas até que sejam

Desenvolvimento de Aplicações Móveis 5

Page 126: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

necessárias. Não ponha inicializações no construtor de MIDlet's ou no método startApp. Apressar a inicialização fará com que a aplicação demore mais para ficar plenamente utilizável. A maioria dos usuários recusaria aplicações que exigem um longo tempo para inicializar. Lembre-se que o tempo de carga da aplicação afeta diretamente a primeira impressão que o usuário tem de seu programa.

2.7. Utilizar arrays (matrizes) ao invés de Collection

Acessar matrizes é mais rápido do que usar um objeto do tipo Vector.

2.8. Utilizar atributos locais

É mais rápido acessar variáveis locais do que variáveis globais.

Desenvolvimento de Aplicações Móveis 6

Page 127: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

3. Tamanho do Arquivo JAR

3.1. Utilizar um ofuscador (obfuscator)

A intenção original do ofuscador é complicar o máximo possível os arquivos da classe compilada para que seja muito complicado reverter essa situação. O Netbeans e o pacote Mobility vêm com um ofuscador. Não está ativo por padrão. Selecione a aba propriedade da aplicação e clique no ícone "Obfuscating":

Figura 1: Ativando o ofuscador

São dez níveis de ofuscação e deve-se ser o mais agressivo possível em se tratando de ofuscamento:

Figura 2: Maximizando o ofuscador

Desenvolvimento de Aplicações Móveis 7

Page 128: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

Entretanto, o processo de ofuscar também reduz o tamanho da aplicação. Um dos métodos empregados pelo ofuscador é renomear as classes utilizando letras simples (por exemplo, classe A). O ofuscador consegue fazer isto por possuir um transformador de métodos. Se o método tiver um modificador private ou protected, então podemos, com segurança, supor que este método não será usado por outros pacotes e poderá, conseqüentemente, ser renomeado sem problemas.

3.2. Compressão dos arquivos JAR

Antes de distribuir seu aplicativo, deve-se comprimir o arquivo JAR final para distribuí-lo. Um arquivo tipo JAR é um arquivo tipo ZIP, e um arquivo tipo ZIP possui diversos níveis de compressão (incluindo a não compressão). O NetBeans não implementa os níveis de compressão.

Figura 3: Comprimindo o arquivo JAR

Para definir a compressão do JAR, abra a janela de propriedades do projeto e selecione a opção “Creating JAR”. Marque a opção “Compress JAR” para comprimir o arquivo final. Não esqueça de gerar (rebuild) o projeto novamente.

O Netbeans armazena o arquivo JAR final na pasta denominada dist abaixo da pasta de projeto. Pode-se renomear a extensão do arquivo JAR para um arquivo com extensão ZIP e abrí-lo com qualquer programa de compressão (exemplo, WinZip) para ver os tamanhos de seus arquivos de classe compilados.

3.3. Evitar a criação de classes desnecessárias

Isto pode parecer contraditório aos princípios da orientação a objetos, entretanto uma classe vazia e simples como:

public class EmptyClass { public EmptyClass(){}}

será compilada em um arquivo do tipo class com com um tamanho de arquivo de no mínimo 250kb (não comprimíveis). Compile esta classe vazia e observe o resultado.

Desenvolvimento de Aplicações Móveis 8

Page 129: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

3.4. Evitar a criação de interfaces

Esta técnica está relacionada com a anteriormente vista. Quanto mais classes e interfaces, mais (kilo)bytes teremos na aplicação final.

3.5. Evitar a criação de classes internas e anônimas

Classes internas (inner class) são classificadas do mesmo modo. Classes anônimas (anonymous class) podem não ter um nome, entretanto ocupam o mesmo espaço nas definições de classe.

3.6. Utilizar um objeto único (padrão Singleton) para múltiplos objetos

Isto reduz o número de classes em sua aplicação. Faça com que seu MIDlet implemente a interface CommandListener e lhe ajudaria a reduzir seu pacote através de uma classe (isso é 250, ou mais, bytes menos).

3.7. Utilizar um pacote "padrão" (não significa não usar package)

Utilize um tamanho de pacote pequeno, encurtando (e não usando) nomes de pacote, o que contribui para a redução dos bytes.

3.8. Utilizar o limite dos inicializadores estáticos

Usando inicializações estáticas, tipo:

int[] tones = { 64, 63, 65, 76, 45, 56, 44, 88 };

seria traduzido pelo compilador de Java nas seguintes declarações:

tones[0] = 64;tones[1] = 63;tones[2] = 65;tones[3] = 76;tones[4] = 45;tones[5] = 56;tones[6] = 44;tones[7] = 88;

Este exemplo ilustra apenas oito elementos. Pense na possibilidade de inicializar centenas de valores que utilizam declarações separadas. Tentar realizar isso, estaria muito acima do tamanho das possíveis aplicações.

Como uma alternativa, é possível utilizar o método getResourceAsStream() para obter valores de um arquivo ou utilizar uma única String para armazenar os valores do array.

3.9. Combinar as imagens em um único arquivo

Imagens são comprimidas melhor quando estão agrupadas em um único arquivo de imagem. Isso é porque a compressão do formato de imagem (formato PNG) é mais específico para imagens do que o método de compressão do arquivo JAR. Há técnicas para se obter uma imagem específica de uma imagem maior, tal como recortá-la.

3.10. Experimentar métodos diferentes de compressão de imagens

Métodos de compressão não são criados de forma semelhante. Alguns podem comprimir melhor alguns tipos de imagem mas podem ter relação de compressão pobre em outros tipos. Escolha um formato de imagem que melhora a relação de compressão. Às vezes, a relação de compressão também é afetada pelo software de imagem que se está utilizando. Experimente com manipulação de imagem diferentes programas para conseguir tamanhos de imagem melhores.

Desenvolvimento de Aplicações Móveis 9

Page 130: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

3.11. Utilizar classes pré-instaladas

Não reinvente a roda. Utilize classes disponíveis na plataforma que está usando. Criar suas classes não só aumenta o tamanho da aplicação como também diminui a estabilidade.

Desenvolvimento de Aplicações Móveis 10

Page 131: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

4. Rede

4.1. Utilizar threads

Utilize uma thread separada para sua função de rede para evitar travamentos da tela.

4.2. Comprimir os dados da rede

Utilize dados comprimidos para diminuir o tráfego de rede da sua aplicação. Isso requerer que seu cliente e servidor estejam utilizando o mesmo protocolo de rede e método de compressão.

Comprimir XML resulta em melhor taxa de compressão porque o XML é representado em formato texto.

4.3. Reduzir o tráfego de rede

Já que as comunicações via rede são lentas e onerosas, tente o quanto mais possível colocar dentro de uma única requisição de rede vários comandos. Isso reduzirá a sobrecarga imposta pelos protocolos de rede.

Desenvolvimento de Aplicações Móveis 11

Page 132: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

5. Uso de Memória

5.1. Utilizar estruturas de dados mais compactas

Utilize estruturas de dados mais amigáveis para memória. Arrays espaçados podem ser representados de outra maneira sem consumir a mesma quantidade de memória.

Existe um equilíbrio quando se otimizando tamanho e velocidade. Utilizar estruturas complexas de dados pode afetar a velocidade de execução do programa.

5.2. Liberar objetos não usados para o Garbage Collector

Libere objetos que não serão mais utilizados para o Garbage Collector – tela, conexões de rede, Registros RMS, entre outros. Ao atribuir para estes objetos o valor nulo, informamos ao Garbage Collector que estes objetos podem ser seguramente descarregados da memória.

5.3. Criar as telas que são raramente usadas como objetos anônimos

Criar os objetos de Tela que são raramente utilizadas (como telas de “auxílio” e “sobre o sistema”) como objetos anônimos libera a necessidade de memória heap, embora tenhamos que pagar o preço por uma carga mais lenta destas telas em particular. A memória heap destas telas supostamente seria ocupada enquanto elas não estivessem sendo usadas e pode ajudar na conservação de memória.

public void commandAction(Command c, Displayable d) { if (c == helpCommand) { display.setCurrent(new HelpForm()); }}

Desenvolvimento de Aplicações Móveis 12

Page 133: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

6. Exercícios

6.1. Outras idéias de otimização

Discuta outras idéias de otimização que possui ou tem em mente ou, ainda, outras técnicas que desenvolveu. Compartilhe-as.

Desenvolvimento de Aplicações Móveis 13

Page 134: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

Módulo 5Desenvolvimento de Aplicações Móveis

Lição 9Pacotes Opcionais

Versão 1.0 - Set/2007

Page 135: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

1. Objetivos

Nesta lição, iremos aprofundar em como escrever, construir, utilizar o emulador e o empacotador de aplicações J2ME. O ambiente de programação que iremos utilizar será o Netbeans.

Nem todos os dispositivos são criados de maneira semelhante, pois cada um deles possui características diferentes. Por isso pode ser muito complicado para se criar uma especificação padrão que atenda a todos os dispositivos.

Para acomodar as diferentes capacidades de cada dispositivo, a tecnologia MIDP definiu vários pacotes opcionais. Esses pacotes são específicos para atender dispositivos específicos que tenham esses recursos. Iremos aprender como utilizar a Mobile Media API (MMAPI) e a Wireless Messaging API (WMA).

Ao final desta lição, o estudante será capaz de:

• Saber quais são as funcionalidade oferecidas pela Mobile Media API• Reproduzir tons simples• Reproduzir um arquivo de áudio de uma rede e de um JAR• Enviar e receber mensagens SMS

Desenvolvimento de Aplicações Móveis 4

Page 136: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

2. Mobile Media API (MMAPI)

A Mobile Media API (MMAPI) permite-nos gerar tons, tocar e gravar áudio e vídeo nos dispositivos compatíveis. A reprodução e a gravação de mídia são tratadas por dois objetos: o DataSource e o Player.

DataSource Player

Figura 1: Relação entre DataSource e Player

O DataSource trata de detalhes de como obter o dado de uma fonte. A fonte pode ser um arquivo de um JAR ou de uma rede (via HTTP), um registro de um RMS, uma conexão de streaming de um servidor ou outra fonte proprietária. O Player não tem o que se preocupar sobre de onde o dado vem ou de que uma maneira ele pode ser obtido. Tudo o que o Player necessita fazer é ler um dado de um DataSource, processar e exibir ou reproduzir a mídia para o dispositivo de saída.

O terceiro ator na nossa cena é o Manager. O Manager cria players de DataSources. O Manager tem métodos para criar Players vindos dos locais de mídia (através de URL), DataSources e InputStreams.

DataSource Player

Manager

Figura 2: Relacionamento do Manager com o DataSource e Player

Pode-se consultar propriedades MMAPI via String System.getProperty(String key).

Chave Descrição

microedition.media.version A versão da especificação MMAPI implementada pelo dispositivo. Exemplo: "1.1"

supports.mixing Retorna "true" se o dispositivo suporta mixagem de áudio. Pode reproduzir os dois últimos tons simultaneamente. Pode ter dois Players reproduzindo áudio simultaneamente e pode reproduzir um tom enquanto o outro Player está reproduzindo áudio ao mesmo tempo.

supports.audio.capture Retorna "true" se a captura de áudio é suportada.

supports.video.capture Retorna "true" se a captura de vídeo é suportada.

supports.recording Retorna "true" se a gravação de áudio é suportada.

2.1. Geração de Tons

Para reproduzir tons é necessário chamar o método estático Manager.playTone(int tom, int duration, int volume). Os valores válidos para o parâmetro tom vão de 0 a 127. O parâmetro duration representa a duração da reprodução do tom e deve ser especificada em milissegundos. O parâmetro volume varia de 0 a 100.

Desenvolvimento de Aplicações Móveis 5

Page 137: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

import javax.microedition.midlet.*;import javax.microedition.lcdui.*;import javax.microedition.media.*;import javax.microedition.media.control.*;import java.io.*;public class ToneMIDlet extends MIDlet implements CommandListener{ private Command exitCommand, playCommand; private Form form; private Gauge volumeGauge; private Gauge durationGauge; private Gauge toneGauge; private Display display; private int duration = 2; // seconds private int volume = 100; private int tone = ToneControl.C4; private static int MAX_VOLUME = 100; private static int MAX_TONE = 127; private static int MAX_DURATION = 5; public ToneMIDlet() { playCommand = new Command("Play", Command.OK, 1); exitCommand = new Command("Exit", Command.EXIT, 1); volumeGauge = new Gauge("Volume", true, MAX_VOLUME, volume); toneGauge = new Gauge("Tone", true, MAX_TONE, tone); durationGauge = new Gauge("Duration",true,MAX_DURATION,duration); form = new Form("Tone Player"); form.addCommand(playCommand); form.addCommand(exitCommand); form.append(volumeGauge); form.append(durationGauge); form.append(toneGauge); } public void startApp() { display = Display.getDisplay(this); form.setCommandListener(this); display.setCurrent(form); } public void pauseApp() {} public void destroyApp(boolean unconditional) {} public void commandAction(Command c, Displayable d) { if (c == exitCommand) { notifyDestroyed(); } if (c == playCommand){ try { volume = volumeGauge.getValue(); tone = toneGauge.getValue(); duration = durationGauge.getValue(); Manager.playTone(tone, duration*1000, volume); } catch (MediaException mex){} } }}

2.2. Tocando Áudio

Por conveniência, o método Manager.createPlayer(String URI) cria um objeto player a partir de uma URI.

import javax.microedition.midlet.*;import javax.microedition.lcdui.*;import javax.microedition.media.*;import javax.microedition.media.control.*;import java.io.*;

Desenvolvimento de Aplicações Móveis 6

Page 138: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

public class NetAudioMidlet extends MIDlet implements CommandListener{ private Command exitCommand, playCommand; private Form form; private Gauge volumeGauge; private Display display; private int volume = 100; private static int MAX_VOLUME = 100; Player player; public NetAudioMidlet() { playCommand = new Command("Play", Command.OK, 1); exitCommand = new Command("Exit", Command.EXIT, 1); volumeGauge = new Gauge("Volume", true, MAX_VOLUME, volume); form = new Form("Audio Player"); form.addCommand(playCommand); form.addCommand(exitCommand); form.append(volumeGauge); } public void startApp() { display = Display.getDisplay(this); form.setCommandListener(this); display.setCurrent(form); try { player = Manager.createPlayer("http://localhost:8084/Chapter07/bong.wav"); player.realize(); player.prefetch(); } catch (IOException ioex) { display.setCurrent(new Alert("IO Exception", ioex.getMessage(), null, AlertType.ERROR)); } catch (MediaException mex) { display.setCurrent(new Alert("Media Exception", mex.getMessage(), null, AlertType.ERROR)); } } public void pauseApp() {} public void destroyApp(boolean unconditional) {} public void commandAction(Command c, Displayable d) { if (c == exitCommand) { notifyDestroyed(); } if (c == playCommand){ try { VolumeControl control = (VolumeControl) player.getControl("VolumeControl"); if (control != null){ control.setLevel(volumeGauge.getValue()); } player.start(); } catch (MediaException mex) { display.setCurrent(new Alert("Media Exception", mex.getMessage(), null, AlertType.ERROR)); } catch (Exception ex){ display.setCurrent(new Alert("Exception", ex.getMessage(), null, AlertType.ERROR)); } } }}

Também é possível tocar uma mídia a partir de um arquivo inserido no JAR do projeto. Entretanto, deve ser criado um objeto do tipo Stream que será repassado para o método Manager.createPlayer().

Desenvolvimento de Aplicações Móveis 7

Page 139: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

import javax.microedition.midlet.*;import javax.microedition.lcdui.*;import javax.microedition.media.*;import javax.microedition.media.control.*;import java.io.*;public class AudioMidlet extends MIDlet implements CommandListener{ private Command exitCommand, playCommand; private Form form; private Gauge volumeGauge; private Display display; private int volume = 100; private static int MAX_VOLUME = 100; Player player; public AudioMidlet() { playCommand = new Command("Play", Command.OK, 1); exitCommand = new Command("Exit", Command.EXIT, 1); volumeGauge = new Gauge("Volume", true, MAX_VOLUME, volume); form = new Form("Audio Player"); form.addCommand(playCommand); form.addCommand(exitCommand); form.append(volumeGauge); } public void startApp() { display = Display.getDisplay(this); form.setCommandListener(this); display.setCurrent(form); } public void pauseApp() {} public void destroyApp(boolean unconditional) {} public void commandAction(Command c, Displayable d) { if (c == exitCommand) { notifyDestroyed(); } if (c == playCommand){ try { InputStream stream = getClass(). getResourceAsStream("bong.wav"); player = Manager.createPlayer(stream, "audio/x-wav"); player.realize(); VolumeControl control = (VolumeControl) player.getControl("VolumeControl"); if (control != null){ control.setLevel(volumeGauge.getValue()); } player.start(); } catch (MediaException mex) { display.setCurrent(new Alert("Media Exception", mex.getMessage(), null, AlertType.ERROR)); } catch (Exception ex){ display.setCurrent(new Alert("Exception", ex.getMessage(), null, AlertType.ERROR)); } } }}

Desenvolvimento de Aplicações Móveis 8

Page 140: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

3. Wireless Messaging API (WMA)

Utilizar o Wireless Messaging API é quase semelhante à maneira que uma conexão é feita através de soquetes e Datagramas. Utiliza-se o mesmo aplicativo – Generic Connection Framework (GCF).

A URL de conexão possui o seguinte formato "sms://+639178888888", onde "+639178888888" é o número do telefone para qual se deseja enviar a mensagem.

public void sendSMS(String number, String message) throws Exception{ String url = "sms://" + number; MessageConnection connection = (MessageConnection) Connector.open(url); TextMessage msg = (TextMessage) connection.newMessage( MessageConnection.TEXT_MESSAGE); msg.setPayloadText(message); connection.send(msg); connection.close();}

3.1. Enviando uma mensagem SMS

O desenvolvimento de aplicações móveis com o Netbeans é muito simples. Não é necessário enviar mensagens reais de SMS apenas para testar a aplicação que estamos desenvolvendo. O Netbeans (com o pacote Mobility) possui a ferramenta J2ME Wireless Toolkit. Esta ferramenta vem com um emulador e inclui também aplicativos para testar o envio e recebimento de mensagens do tipo SMS. É possível configurar o número do telefone utilizando as preferências do WMA acessando a partir do menu principal:

• Tools

• Java Platform Manager

• J2ME Wireless Toolkit 2.2

• Tools & Extensions

• Preferences -> WMA

• Utilities -> WMA: Open Console

Figura 3: Java Platform Manager

Desenvolvimento de Aplicações Móveis 9

Page 141: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

Figura 4: Java Platform Manager - Devices

Figura 5: Java Platform Manager – Tools & Extensions

Desenvolvimento de Aplicações Móveis 10

Page 142: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

Figura 6: J2ME Wireless Toolkit – Preferences

Figura 7: J2ME Wireless Toolkit – Utilities e Console

import javax.microedition.midlet.*;import javax.microedition.lcdui.*;import javax.microedition.io.*;import javax.wireless.messaging.*;public class SMSMidlet extends MIDlet implements CommandListener, Runnable { private Command exitCommand, sendCommand;

Desenvolvimento de Aplicações Móveis 11

Page 143: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

private Form form; private TextField addressField, mesgField; private Display display; public SMSMidlet() { sendCommand = new Command("Send", Command.OK, 1); exitCommand = new Command("Exit", Command.EXIT, 1); addressField = new TextField( "Phone Number", "+5550000", 32, TextField.ANY); mesgField = new TextField( "Message", "hello, world!", 160, TextField.ANY); form = new Form("SMS Message"); form.append(addressField); form.append(mesgField); form.addCommand(sendCommand); form.addCommand(exitCommand); } public void startApp() { display = Display.getDisplay(this); form.setCommandListener(this); display.setCurrent(form); } public void pauseApp() {} public void destroyApp(boolean unconditional) {} public void commandAction(Command c, Displayable d) { if (c == exitCommand) { notifyDestroyed(); } if (c == sendCommand) { Thread thread = new Thread( this ); thread.start(); } } public void sendSMS(String number, String message) throws Exception{ String url = "sms://" + number; MessageConnection connection = (MessageConnection) Connector.open(url); TextMessage msg = (TextMessage) connection.newMessage( MessageConnection.TEXT_MESSAGE); msg.setPayloadText(message); connection.send(msg); connection.close(); } public void run() { try { String address = addressField.getString(); String message = mesgField.getString(); sendSMS(address, message); display.setCurrent(new Alert("SMS Message", "Message Sent\n" + "To: " + address + "\n" + "Message: " + message, null, AlertType.INFO)); } catch (Exception ex) { display.setCurrent(new Alert("SMS Error", ex.getMessage(), null, AlertType.ERROR)); } } }

Desenvolvimento de Aplicações Móveis 12

Page 144: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

Figura 8: Execução da aplicação

3.2. Recebendo mensagens SMS

Para receber um mensagem de texto, abra uma MessageConnection especificando uma porta. O Protocolo para mensagem SMS é "sms". Este comando ficará esperando até receber uma mensagem de SMS pela porta 8888:

conn = (MessageConnection) Connector.open("sms://:8888");

Devemos registrar nossa aplicação para ser um receptor da mensagem de forma que o AMS notifique o MIDlet da chegada da mensagem.

conn.setMessageListener(this);

O método notifyIncomingMessage será chamado pelo AMS quando uma mensagem for recebida

Desenvolvimento de Aplicações Móveis 13

Page 145: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

pelo dispositivo. Precisamos criar uma Thread separada para as mensagens de leitura de forma que o método que for chamado novamente possa ter uma saída imediata.

public void notifyIncomingMessage(MessageConnection messageConnection) { if (thread == null){ thread = new Thread(this); thread.start(); }}

E, deste modo, será utilizado o método run(), do qual obteremos a mensagem:

public void run(){ try { Message mesg = conn.receive(); if (mesg != null && mesg instanceof TextMessage) { TextMessage text = (TextMessage) mesg; addressField.setText(text.getAddress()); mesgField.setText(text.getPayloadText()); dateField.setText("" + text.getTimestamp()); statusField.setText("Message received."); } } catch (Exception e) { statusField.setText("Error: " + e.getMessage()); } thread = null; }

Este é o código completo para receber e listar a mensagem SMS:

import javax.microedition.midlet.*;import javax.microedition.lcdui.*;import javax.microedition.io.*;import javax.wireless.messaging.*;public class SMSReceiverMidlet extends MIDlet implements CommandListener, MessageListener, Runnable { private Command exitCommand, sendCommand; private Form form; private StringItem statusField, addressField, mesgField, dateField; private Display display; private MessageConnection conn; private Thread thread; private String port = "8888"; public SMSReceiverMidlet() { exitCommand = new Command("Exit", Command.EXIT, 1); statusField = new StringItem("Status:", ""); addressField = new StringItem("From:", ""); mesgField = new StringItem("Message:", ""); dateField = new StringItem("Timestamp:", ""); form = new Form("SMS Receiver"); form.append(statusField); form.append(addressField); form.append(mesgField); form.append(dateField); form.addCommand(exitCommand); } public void startApp() { display = Display.getDisplay(this); form.setCommandListener(this); startReceiver(); display.setCurrent(form); } public void pauseApp() { thread = null;

Desenvolvimento de Aplicações Móveis 14

Page 146: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

} public void destroyApp(boolean unconditional) { thread = null; if (conn != null){ try { conn.close(); } catch (Exception ex){} } } public void commandAction(Command c, Displayable d) { if (c == exitCommand) { notifyDestroyed(); } } private void startReceiver(){ try { String addr = "sms://:" + port; if (conn == null){ conn = (MessageConnection) Connector.open(addr); conn.setMessageListener(this); statusField.setText( "waiting for message at port " + port); } } catch (Exception ex){ statusField.setText("Cannot open connection on port " + port + ":" + ex.getMessage()); } thread = new Thread(this); thread.start(); } public void notifyIncomingMessage(MessageConnection messageConn) { if (thread == null){ thread = new Thread(this); thread.start(); } } public void run(){ try { Message mesg = conn.receive(); if (mesg != null && mesg instanceof TextMessage) { TextMessage text = (TextMessage) mesg; addressField.setText(text.getAddress()); mesgField.setText(text.getPayloadText()); dateField.setText("" + text.getTimestamp()); statusField.setText("Message received."); } else { statusField.setText( "Non-text message received: " + mesg.getClass().toString()); } } catch (Exception e) { statusField.setText("Error: " + e.getMessage()); } thread = null; }}

Desenvolvimento de Aplicações Móveis 15

Page 147: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

Figura 9: Recebimento da mensagem

Desenvolvimento de Aplicações Móveis 16

Page 148: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

4. Exercícios

4.1. Tocador de áudio

Crie uma MIDlet que toque um arquivo de áudio por um número indefinido de vezes. O arquivo de áudio deve ser lido a partir do JAR da aplicação. Dica: envie uma propriedade para o objeto Player controlar o laço.

4.2. Auto-respondedor de SMS

Crie uma MIDlet que responda automaticamente quando receber uma mensagem de texto. Dica: modifique a classe SMSReceiverMidlet e utilize a mesma conexão para enviar a mensagem de resposta.

Desenvolvimento de Aplicações Móveis 17

Page 149: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

Módulo 5Desenvolvimento de Aplicações Móveis

Lição 10Outros Tópicos

Versão 1.0 - Set/2007

Page 150: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

1. Objetivos

Timers e TimeTasks permitem programar tarefas para que sejam executadas em um horário determinado. A tarefa pode ainda ser programada para que se repita num intervalo de tempo designado pelo programador.

Ao final desta lição, o estudante será capaz de:

• Programar tarefas utilizando Timers (marcadores)• Registrar o recebimento de conexões no Registro

Desenvolvimento de Aplicações Móveis 4

Page 151: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

2. Timers

É possível criar uma tarefa utilizando-se a herança, estendendo a classe TimerTask e implementando o método run(). Este método será executado baseado na programação do Timer.

class CounterTask extends TimerTask { int counter = 0; public void run() { System.out.println("Counter: " + counter++); }}

Para programar uma tarefa, cria-se um objeto do tipo Timer e utiliza-se o método schedule() do Timer para que se possa configurar o andamento da tarefa. Cada Timer roda em uma thread independente. O método schedule() possui várias formas diferentes. É possível especificar o tempo de início para a tarefa utilizando um tempo em milissegundos ou especificando uma data absoluta (java.util.Date). O terceiro parâmetro para o método é o período de repetição da tarefa. Se o período de repetição for especificado, a tarefa será executada a cada "período" de milissegundos definido.

Timer timer = new Timer();TimerTask task = new CounterTask();// inicia a tarefa em 8 segundos, e repete a cada segundotimer.schedule(task, 8000, 1000);

Para parar a execução do objeto Timer, utiliza-se o método close(). Isto fará com que a Thread contendo o Timer seja interrompida e a tarefa agendada, descartada. Lembre-se sempre de que uma vez que o Timer tenha sido parado, não poderá ser reiniciado.

void schedule( TimerTask task, long delay)

Agendar a tarefa para que seja executada a cada período (em milissegundos).

void schedule( TimerTask task, long delay, long period)

Agendar a tarefa para que ela seja repetida, começando após o período especificado (em milissegundos).

void schedule( TimerTask task, Date time)

Agenda a tarefa para que seja executada num tempo específico.

void schedule( TimerTask task, Date time, long period)

Agenda a tarefa para que ela seja repetida, começando pelo tempo especificado.

void cancel() Interrompe o timer e descarta qualquer tarefa agendada.

import javax.microedition.midlet.*;import javax.microedition.lcdui.*;import java.io.*;import java.util.Timer;import java.util.TimerTask;import java.util.Date;public class TimerMidlet extends MIDlet implements CommandListener{ private Command exitCommand; private Form form; private StringItem textField; private Display display; private Timer timer; public TimerMidlet() { exitCommand = new Command("Exit", Command.EXIT, 1); textField = new StringItem("Counter", ""); timer = new Timer();

Desenvolvimento de Aplicações Móveis 5

Page 152: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

TimerTask task = new CounterTask(this); timer.schedule(task, 2000, 1000); form = new Form("Timer Test"); form.addCommand(exitCommand); form.append(textField); } public void startApp() { display = Display.getDisplay(this); form.setCommandListener(this); display.setCurrent(form); } public void pauseApp() {} public void destroyApp(boolean unconditional) { timer.cancel(); } public void commandAction(Command c, Displayable d) { if (c == exitCommand) { destroyApp(true); notifyDestroyed(); } } public void setText(String text){ textField.setText(text); }}class CounterTask extends TimerTask { int counter = 0; TimerMidlet midlet; public CounterTask(TimerMidlet midlet){ this.midlet = midlet; } public void run() { counter++; midlet.setText("" + counter); System.out.println("Counter: " + counter); }}

Desenvolvimento de Aplicações Móveis 6

Page 153: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

3. Registro de Conexões

Permite que os MIDlets registrem as conexões com o software de gerenciamento da aplicação (AMS). Se o programa não estiver em execução, o AMS ficará esperando por conexões nos limites dos endereços registrados pelas aplicações. Quase todos os tipos de conexões são suportadas, incluindo SMS, CBS e AMS.

É possível fazer o registro de novas conexões de duas maneiras: da maneira estática, utilizando o arquivo application descriptor (JAD), ou dinamicamente durante o tempo de execução, utilizando a API PushRegistry.

Iremos demostrar como utilizar a API PushRegistry. Pressionar o botão direito do mouse sobre o Project Name e selecionar properties para abrir a página de propriedades do projeto. Selecionar a opção de Push Registry.

Figura 1: Janela de Propriedades do Projeto

Pressionar o botão add... para registrar uma nova conexão:

Figura 2: Adicionando um novo registro

Class Name: SMSReceiveMidletSender IP: *

Desenvolvimento de Aplicações Móveis 7

Page 154: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

Connection String: sms://:50000

Verifique a conexão adicionada na figura abaixo.

Figura 3: Registro da Conexão

Selecionar a opção API Permissions e pressionar o botão Add para inserir uma permissão do MIDlet para uma biblioteca em particular.

Figura 4: Adicionando permissões

Adicionar as seguintes bibliotecas:

javax.microedition.io.PushRegistryjavax.microedition.io.Connector.smsjavax.wireless.messaging.sms.receivejavax.wireless.messaging.sms.send

Desenvolvimento de Aplicações Móveis 8

Page 155: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

Figura 5: Permissões adicionadas

Para finalizar, criar um atributo para configurar automaticamente a porta, selecionar Attributes conforme a seguinte janela:

Figura 6: Adicionar novos atributos

Pressionar o botão Add... para adicionar um novo atributo do tipo Custom.

Desenvolvimento de Aplicações Móveis 9

Page 156: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

Figura 7: Adicionando o atributo

Encerre a janela de configuração do projeto pressionando o botão OK e execute a suite do MIDlet. Executar a aplicação duas vezes para conseguir dois emuladores conforme as figuras:

Figura 8: Emulador do aplicativo

Observe que o primeiro telefone possui o número +5550000 e o segundo +5550001. Selecionar a opção SMSReceiveMidlet no primeiro telefone. Uma mensagem solicitando a autorização para comunicação via mensagem será mostrada, selecionar a opção Yes e deixar em modo de espera:

Figura 9: Modo de Espera da Mensagem

Desenvolvimento de Aplicações Móveis 10

Page 157: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

No segundo telefone, selecionar SMSSendMidlet, informar o endereço 5550000 e pressionar OK.

Figura 10: Emulador do aplicativo

Digitar uma mensagem e pressionar Send:

Figura 11: Janela de confirmação

Responder afirmativamente à mensagem de confirmação da comunicação:

Figura 12: Confirmação da Comunicação

Responder afirmativamente a próxima mensagem e aguardar o envio. Observar no primeiro telefone o recebimento da mensagem.

Figura 13: Aplicativo concluído

Desenvolvimento de Aplicações Móveis 11

Page 158: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

3.1. Programas

Classe Auxiliar

import javax.microedition.io.*;import javax.microedition.lcdui.*;import javax.wireless.messaging.*;import java.io.IOException;public class SMSSender implements CommandListener, Runnable { Command sendCommand = new Command("Send", Command.OK, 1); Command backCommand = new Command("Back", Command.BACK, 2); Display display; String smsPort; String destinationAddress; TextBox messageBox; Displayable backScreen; Displayable sendingScreen; public SMSSender(String smsPort, Display display, Displayable backScreen, Displayable sendingScreen) { this.smsPort = smsPort; this.display = display; this.destinationAddress = null; this.backScreen = backScreen; this.sendingScreen = sendingScreen; messageBox = new TextBox("Enter Message", null, 65535, TextField.ANY); messageBox.addCommand(backCommand); messageBox.addCommand(sendCommand); messageBox.setCommandListener(this); } public void promptAndSend(String destinationAddress) { this.destinationAddress = destinationAddress; display.setCurrent(messageBox); } public void commandAction(Command c, Displayable s) { try { if (c == backCommand) { display.setCurrent(backScreen); } else if (c == sendCommand) { display.setCurrent(sendingScreen); new Thread(this).start(); } } catch (Exception ex) { ex.printStackTrace(); } } public void run() { String address = destinationAddress + ":" + smsPort; MessageConnection smsconn = null; try { smsconn = (MessageConnection)Connector.open(address); TextMessage txtmessage = (TextMessage)smsconn.newMessage( MessageConnection.TEXT_MESSAGE); txtmessage.setAddress(address); txtmessage.setPayloadText(messageBox.getString()); smsconn.send(txtmessage); } catch (Throwable t) { System.out.println("Send caught: "); t.printStackTrace(); } if (smsconn != null) { try { smsconn.close(); } catch (IOException ioe) { System.out.println("Closing connection caught: ");

Desenvolvimento de Aplicações Móveis 12

Page 159: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

ioe.printStackTrace(); } } }}

Midlet para receber mensagem SMS

import javax.microedition.midlet.*;import javax.microedition.io.*;import javax.microedition.lcdui.*;import javax.wireless.messaging.*;import java.io.IOException;public class SMSReceiveMidlet extends MIDlet implements CommandListener, Runnable, MessageListener { Command exitCommand = new Command("Exit", Command.EXIT, 2); Command replyCommand = new Command("Reply", Command.OK, 1); Alert content; Display display; Thread thread; String[] connections; boolean done; String smsPort; MessageConnection smsconn; Message msg; String senderAddress; Alert sendingMessageAlert; SMSSender sender; Displayable resumeScreen; public SMSReceiveMidlet() { smsPort = getAppProperty("SMS-Port"); display = Display.getDisplay(this); content = new Alert("SMS Receive"); content.setTimeout(Alert.FOREVER); content.addCommand(exitCommand); content.setCommandListener(this); content.setString("Receiving..."); sendingMessageAlert = new Alert("SMS", null, null, AlertType.INFO); sendingMessageAlert.setTimeout(5000); sendingMessageAlert.setCommandListener(this); sender = new SMSSender(smsPort, display, content, sendingMessageAlert); resumeScreen = content; } public void startApp() { String smsConnection = "sms://:" + smsPort; if (smsconn == null) { try { smsconn = (MessageConnection) Connector.open(smsConnection); smsconn.setMessageListener(this); } catch (IOException ioe) { ioe.printStackTrace(); } } connections = PushRegistry.listConnections(true); if (connections == null || connections.length == 0) { content.setString("Waiting for SMS on port " + smsPort + "..."); } done = false; thread = new Thread(this); thread.start(); display.setCurrent(resumeScreen); } public void notifyIncomingMessage(MessageConnection conn) { if (thread == null) {

Desenvolvimento de Aplicações Móveis 13

Page 160: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

done = false; thread = new Thread(this); thread.start(); } } public void run() { try { msg = smsconn.receive(); if (msg != null) { senderAddress = msg.getAddress(); content.setTitle("From: " + senderAddress); if (msg instanceof TextMessage) { content.setString(((TextMessage)msg).getPayloadText()); } else { StringBuffer buf = new StringBuffer(); byte[] data = ((BinaryMessage)msg).getPayloadData(); for (int i = 0; i < data.length; i++) { int intData = (int)data[i] & 0xFF; if (intData < 0x10) { buf.append("0"); } buf.append(Integer.toHexString(intData)); buf.append(' '); } content.setString(buf.toString()); } content.addCommand(replyCommand); display.setCurrent(content); } } catch (IOException e) { // e.printStackTrace(); } } public void pauseApp() { done = true; thread = null; resumeScreen = display.getCurrent(); } public void destroyApp(boolean unconditional) { done = true; thread = null; if (smsconn != null) { try { smsconn.close(); } catch (IOException e) { // Ignora erros no caso de finalização } } } public void commandAction(Command c, Displayable s) { try { if (c == exitCommand || c == Alert.DISMISS_COMMAND) { destroyApp(false); notifyDestroyed(); } else if (c == replyCommand) { reply(); } } catch (Exception ex) { ex.printStackTrace(); } } private void reply() { String address = senderAddress.substring(6); String statusMessage = "Sending message to " + address + "..."; sendingMessageAlert.setString(statusMessage); sender.promptAndSend(senderAddress); }

Desenvolvimento de Aplicações Móveis 14

Page 161: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

}

Midlet para enviar mensagem SMS

import javax.microedition.midlet.*;import javax.microedition.io.*;import javax.microedition.lcdui.*;import javax.wireless.messaging.*;import java.io.IOException;public class SMSSendMidlet extends MIDlet implements CommandListener { Command exitCommand = new Command("Exit", Command.EXIT, 2); Command okCommand = new Command("OK", Command.OK, 1); Display display; String smsPort; TextBox destinationAddressBox; Alert errorMessageAlert; Alert sendingMessageAlert; SMSSender sender; Displayable resumeScreen = null; public SMSSendMidlet() { smsPort = getAppProperty("SMS-Port"); display = Display.getDisplay(this); destinationAddressBox = new TextBox("Destination Address?", null, 256, TextField.PHONENUMBER); destinationAddressBox.addCommand(exitCommand); destinationAddressBox.addCommand(okCommand); destinationAddressBox.setCommandListener(this); errorMessageAlert = new Alert("SMS", null, null, AlertType.ERROR); errorMessageAlert.setTimeout(5000); sendingMessageAlert = new Alert("SMS", null, null, AlertType.INFO); sendingMessageAlert.setTimeout(5000); sendingMessageAlert.setCommandListener(this); sender = new SMSSender(smsPort, display, destinationAddressBox, sendingMessageAlert); resumeScreen = destinationAddressBox; } public void startApp() { display.setCurrent(resumeScreen); } public void pauseApp() { resumeScreen = display.getCurrent(); } public void destroyApp(boolean unconditional) { } public void commandAction(Command c, Displayable s) { try { if (c == exitCommand || c == Alert.DISMISS_COMMAND) { destroyApp(false); notifyDestroyed(); } else if (c == okCommand) { promptAndSend(); } } catch (Exception ex) { ex.printStackTrace(); } } private void promptAndSend() { String address = destinationAddressBox.getString(); if (!SMSSendMidlet.isValidPhoneNumber(address)) { errorMessageAlert.setString("Invalid phone number"); display.setCurrent(errorMessageAlert, destinationAddressBox); return; } String statusMessage = "Sending message to " + address + "..."; sendingMessageAlert.setString(statusMessage);

Desenvolvimento de Aplicações Móveis 15

Page 162: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

sender.promptAndSend("sms://" + address); } private static boolean isValidPhoneNumber(String number) { char[] chars = number.toCharArray(); if (chars.length == 0) { return false; } int startPos = 0; if (chars[0] == '+') { startPos = 1; } for (int i = startPos; i < chars.length; ++i) { if (!Character.isDigit(chars[i])) { return false; } } return true; }}

Desenvolvimento de Aplicações Móveis 16

Page 163: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

4. Exercícios

4.1. Relógio no Celular

Criar um MIDlet que mostre a data e hora atual e que seja atualizada a cada segundo. Utilize um Timer para atualizar a data e hora e um StringItem para exibi-las.

Desenvolvimento de Aplicações Móveis 17

Page 164: Projeto JEDI - Desenvolvimento de Aplicações Móveis - Java - 164 páginas

JEDITM

Parceiros que tornaram JEDITM possível

Instituto CTSPatrocinador do DFJUG.

Sun MicrosystemsFornecimento de servidor de dados para o armazenamento dos vídeo-aulas.

Java Research and Development Center da Universidade das FilipinasCriador da Iniciativa JEDITM.

DFJUGDetentor dos direitos do JEDITM nos países de língua portuguesa.

Banco do BrasilDisponibilização de seus telecentros para abrigar e difundir a Iniciativa JEDITM.

PolitecSuporte e apoio financeiro e logístico a todo o processo.

BorlandApoio internacional para que possamos alcançar os outros países de língua portuguesa.

Instituto Gaudium/CNBBFornecimento da sua infra-estrutura de hardware de seus servidores para que os milhares de alunos possam acessar o material do curso simultaneamente.

Desenvolvimento de Aplicações Móveis 18