Feed Artigos Comentários

Arquivo de Novembro de 2006



Dicas & Banco de Dados Hildebrando em 28 Nov 2006

Oracle para desenvolvedores Java

Estou fazendo uma analogia a um artigo publicado na Java Magazine com o titulo ‘MySQL para desenvolvedores Java’. Minha principal motivação é uma recente instalação/configuração de um Oracle aqui na empresa.

Se você é um desenvolvedor então a sua função é produzir código, fazer levantamentos, criar modelos e afins. Toda a responsabilidade do banco de dados fica por conta do DBA da empresa. E o papel (Database Administrator) exige uma administração completa do banco, com acompanhamentos, configurações, otimizações. Porém você não precisa se tornar um DBA, mas pode te ajudar em algumas situações se voce souber o necessário.

1 - Instalação

O download é gratuito, basta acessar a pagina da Oracle e lá você encontrara a versão do banco que deseja.

A instalação no Windows é muito facil, tanto que muitos livros preferem abordar apenas instalações em Unix/Linux pois nestes é necessário algumas configurações. É o famoso NNF (Next,Next,Finish). E voce deve utilizar assim mesmo. Nosso objetivo não é customiza-lo, e sim utiliza-lo.

2 - Estrutura

Depois que o Oracle foi instalado é criado alguns usuarios padrão. O mais importante é o SYS. Ele é o usuario com perfil ADM para a instancia do banco que foi criada. Você deve utilizar o banco ORCL, o padrão configurado pelo Oracle.

Administre o banco pela interface WEB. Cada banco fica em uma porta, portanto acesse a padrão:

http://localhost:5500/em (A porta pode variar)

login : SYS
senha :
perfil : SYSDBA

3 - Usuarios

O Oracle trabalha focado nos usuarios, ou seja, quando é criado um usuario junto é criado um schema com mesmo nome. Portanto crie quantos usuarios forem necessários. Após a criação dos usuarios, faça o login com os mesmos e assim siga criando as estruturas como Tabelas, Sinonimos, Triggers, Indices, Sequences, etc.

4 - Acessando do Java

Não se preocupe em baixar o client do Oracle, pois o driver JDBC consegue fazer a integração tranquilamente. Para baixar o driver novamente acesse o endereço da Oracle e adicione o jar no seu CLASSPATH. O unico detalhe é quanto a url de conexao.

jdbc:oracle:thin:@localhost:1521:ORCL

Versões mais antigas do Oracle, para voce conseguir executar sem o client instalado.

jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=ORCL)))

lembre-se de utilizar o usuario criado anteriormente para acessar as tabelas.

5 - Conclusão

É isso ai. Não tem segredo. O resto esta relacionado com tarefas de administração, inclusive toda a parte de dar direitos e tudo mais. Pode parecer simples mas o mundo ADM é uma outra realidade. Um DBA tem preocupações com um foco diferente, inclusive o Oracle é tem a fama do banco com mais parafusos para apertar, cada uma com uma função que pode ajudar muito no gerenciamento dos dados.

Java Hildebrando em 24 Nov 2006

Trabalhando imagens com Java.

A API de Java para tratamento de imagens é bem complexa. Envolve decodificadores, renderizadores, byte[] para ca, byte[] para la, BufferedImage, etc. Para servir de repositorio tanto para mim quanto para quem visitar esta pagina sempre que eu (ou alguem que ajudar) desenvolver um novo util para tratar imagens eu posto aqui.


public static void gerarThumbnail(InputStream inputStream, OutputStream out, int thumbAltura, float quality) throws Exception{

Image image = null;
int largura = 0;
int altura = 0;

try {
//Recuperar os valores de LARGURA/ALTURA e ALTERAR no registro da FOTO
image = ImageIO.read(inputStream);
largura = image.getWidth(null);
altura = image.getHeight(null);
} catch (Exception e) {
throw new Exception("ERRO ALTERANDO TAMANHO DA IMAGEM " + e);
}

try {

//Fazer a geracao do TumbNail levando em conta o tamanho da ALTURA
MediaTracker mediaTracker = new MediaTracker(new Container());
mediaTracker.addImage(image, 0);
mediaTracker.waitForID(0);

// determine thumbnail size from WIDTH and HEIGHT
double thumbPorcentagem = ((thumbAltura*100.0)/altura)/100.0;
int thumbLargura = (int)(largura * thumbPorcentagem);

// draw original image to thumbnail image object and
// scale it to the new size on-the-fly
BufferedImage thumbImage = new BufferedImage(thumbLargura,thumbAltura, BufferedImage.TYPE_INT_RGB);
Graphics2D graphics2D = thumbImage.createGraphics();
graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BICUBIC); //For speed better use RenderingHints.VALUE_INTERPOLATION_BILINEAR
graphics2D.drawImage(image, 0, 0, thumbLargura, thumbAltura, null);

// save thumbnail image to OUTFILE
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(thumbImage);

param.setQuality(quality, false); //The quality argument from the command line is converted from the interval 0 to 100 to the interval 0.0f to 1.0f, because that's what the codec expects (I mostly use 0.75f).
encoder.setJPEGEncodeParam(param);
encoder.encode(thumbImage);
out.close();

} catch (Exception e) {
throw new Exception("ERRO SALVANDO O THUMBNAIL DA IMAGEM " + e);
}
}

public static void gerarWatermark(InputStream imagemOriginal, InputStream imagemWatermark, OutputStream imagemGerada){

try {

BufferedImage im = ImageIO.read(imagemOriginal);
BufferedImage im2 = ImageIO.read(imagemWatermark);
Graphics2D g = im.createGraphics();
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.4f));
g.drawImage(im2, (im.getWidth()-im2.getWidth())/2, (im.getHeight()-im2.getHeight())/2, null);
g.dispose();
ImageIO.write(im, "jpeg", imagemGerada);

} catch (Exception e) {
System.out.println(e);
}
}

public static void gerarWatermark(InputStream imagemOriginal, String textoWatermark, OutputStream imagemGerada){

try {

BufferedImage im = ImageIO.read(imagemOriginal);

//Preparando o Graphics 2D para incluir o texto na imagem
Graphics2D g = im.createGraphics();
g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

//Setar a font utilizada no texto
g.setFont(new Font("Lucida Bright", Font.ITALIC, 60));

//Efeitos de rotacao no texto
g.rotate(-Math.PI/4, im.getWidth()/2, im.getHeight()/2);

//Setando o valor do texto
TextLayout tl = new TextLayout(textoWatermark, g.getFont(), g.getFontRenderContext());

//???
Rectangle2D bounds = tl.getBounds();
double x = (im.getWidth()-bounds.getWidth())/2 - bounds.getX();
double y = (im.getHeight()-bounds.getHeight())/2 - bounds.getY();

//
Shape outline = tl.getOutline(AffineTransform.getTranslateInstance(x+2, y+1));

//Montando a saida
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.3f));
g.setPaint(Color.WHITE);
g.draw(outline);
g.setPaint(new GradientPaint(0, 0, Color.WHITE, 30, 20, new Color(128,128,255), true));
tl.draw(g, (float)x, (float)y);
g.dispose();

ImageIO.write(im, "jpeg", imagemGerada);

} catch (Exception e) {
System.out.println(e);
}
}

Desenvolvimento de Software Hildebrando em 05 Nov 2006

Convention over Configuration

Você só deve configurar aquilo que for específico, o que for padrão deve ser utilizado normalmente. Assim como padrões de projeto talvez você ja utilize mas nem sabia, portanto aqui vai um exemplo.

Imagine que você tem uma tela de edição de dados de uma pessoa. Junto a esta tela você tem o Controller (Servlet), o objeto de dominio (POJO) e a tabela PESSOA. Além desta tela você tem outra tela de pesquisa de pessoas. Se você seguir o padrão de nomenclatura, por exemplo. A Classe Pessoa esta ligada a tabela PESSOA, por tanto o arquivo de tela é o Pessoa.jsp você esta seguindo uma determinada convenção, evitando criar arquivos de configuração para montar o fluxo.

O conceito é bem simples. Para as situações normais basta seguir as convenções que o seu sistema ja deve estar preparado para tratar estes padrões.

Com o Struts uma forma interessante da utilização de CoC é com os wildcards das Actions. Se todas as suas Actions forem SalvarProduto, SalvarCliente, SalvarPedido você pode declarar a Action Salvar* , e por convenção pode se chegar ao componente de serviço ou de domínio.

Um link sobre o assunto Struts - Wildcard http://www.twdata.org/struts-wildcard/

Desenvolvimento de Software Hildebrando em 05 Nov 2006

A produtividade de Ruby on Rails - I.

Você ja teve ter ouvido falar de uma nova linguagem que pretende revolucionar o desenvolvimento de software. Ele chama Ruby e foi inventada a algum tempo visando produtividade.

Eu olho novas tecnologias com uma certa desconfiança, isso se deve a inumeras que ja vi chegar, ficar e passar. Porém vou começar um estudo pesado em Ruby pois pode contribuir com o nosso processo.

A Linguagem Ruby é uma linguagem bem simples, com tipagem fraca e outros recursos mais dinâmicos.

Sugiro o tutorial http://kb.reflectivesurface.com/br/tutoriais/rubyOnRails/

1 - Comece fazendo o download do Ruby.

2 - De uma analisada na documentação. Se você tem uma base de OO vai entender o porque da linguagem simples.

3 - Na instalação Windows (que eu utilizei) você ira encontrar um aplicativo chamado de RubyGems. É como se fosse um gerenciador de pacotes. Portanto qualquer novo pacote deve ser feito utilizando seus comandos. O pacote que iremos utilizar é o Rails.

gem install rails --include-dependencies

Na instalação ja foi adicionado no PATH o diretorio /ruby/bin.

Devido a todas as dependencias a instalação demora alguns minutos. Infelizmente sem barra de progresso portanto tenha paciência se a tela ficar estática por um tempo. O resultado final deve ser :


Bulk updating Gem source index for: http://gems.rubyforge.org
Successfully installed rails-1.1.6
Successfully installed activesupport-1.3.1
Successfully installed activerecord-1.14.4
Successfully installed actionpack-1.12.5
Successfully installed actionmailer-1.2.5
Successfully installed actionwebservice-1.1.6
Installing ri documentation for activesupport-1.3.1...
Installing ri documentation for activerecord-1.14.4...
Installing ri documentation for actionpack-1.12.5...
Installing ri documentation for actionmailer-1.2.5...
Installing ri documentation for actionwebservice-1.1.6...
Installing RDoc documentation for activesupport-1.3.1...
Installing RDoc documentation for activerecord-1.14.4...
Installing RDoc documentation for actionpack-1.12.5...
Installing RDoc documentation for actionmailer-1.2.5...
Installing RDoc documentation for actionwebservice-1.1.6...

4 - Após a instalação vamos criar a estrutura básica de uma aplicação WEB.

rails c:\ruby\hellorails

Este processo é bem rápido e ao fim você tem uma estrutura de diretórios :

+ app
+ components
+ config
+ db
+ doc
+ lib
+ log
+ public
+ script
+ test
+ tmp
+ vendor
+ Rakefile
+ README

Entre no diretório

cd c:\ruby\hellorails

Inicie o servidor

ruby script/server

=> Booting WEBrick...
=> Rails application started on http://0.0.0.0:3000
=> Ctrl-C to shutdown server; call with --help for options
[2006-11-04 20:59:05] INFO WEBrick 1.3.1
[2006-11-04 20:59:05] INFO ruby 1.8.4 (2006-04-14) [i386-mswin32]
[2006-11-04 20:59:05] INFO WEBrick::HTTPServer#start: pid=3732 port=3000

Se tudo funcionou como o previsto basta acessar o servidor no endereco http://localhost:3000

5 - Vamos começar nosso projeto fazendo o famoso CRUD (Create,Retrieve,Update,Delete). Para integrar com o MySQL voce precisa alterar o arquivo config/database.yml.


gem install mysql

Select which gem to install for your platform (i386-mswin32)
1. mysql 2.7.1 (mswin32)
2. mysql 2.7 (ruby)
3. mysql 2.6 (ruby)
4. mysql 2.5.1 (ruby)
5. Cancel installation
> 1
Successfully installed mysql-2.7.1-mswin32
Installing ri documentation for mysql-2.7.1-mswin32...
Installing RDoc documentation for mysql-2.7.1-mswin32...

Copie o arquivo libmysql.dll que esta localizado no diretorio bin do MySQL para o diretorio bin do ruby.

6 - O Rails utiliza o modelo MVC como sua estrutura camadas, por tanto execute “ruby script/generate” para criar seus arquivos “controller” e “model”.

6.1 - Controller

C:\ruby\hellorails>ruby script/generate controller Produto editar pesquisar
exists app/controllers/
exists app/helpers/
create app/views/produto
exists test/functional/
create app/controllers/produto_controller.rb
create test/functional/produto_controller_test.rb
create app/helpers/produto_helper.rb
create app/views/produto/editar.rhtml
create app/views/produto/pesquisar.rhtml

“ruby script/generate controller Produto editar pesquisar”

Produto = É o nome do controller
editar = É o nome de uma View
pesquisar = É o nome de outra View

6.2 - Model

C:\ruby\hellorails>ruby script/generate model Produto
exists app/models/
exists test/unit/
exists test/fixtures/
create app/models/produto.rb
create test/unit/produto_test.rb
create test/fixtures/produtos.yml
create db/migrate
create db/migrate/001_create_produtos.rb

“ruby script/generate model Produto”
Produto = É o nome do Model

7 - Para testar se esta tudo funcionando você deve configurar suas paginas no arquivo app/controllers/produto_controller.rb

class ProdutoController < ApplicationController

def index
render_text "Hello, world! Pagina principal"
end

def editar
render_text "Hello, world! Editar"
end

def pesquisar
render_text "Hello, world! Pesquisar"
end
end

Cada def contida no arquivo representa seu método e este indica cada requisição. Portanto para entrar no metodo pesquisar basta acessar a pagina http://localhost:3000/produto/pesquisar

8 - Para completar o fluxo precisamos criar um novo componente view. Na verdade este ja foi criado no momento que criamos o controller, portanto basta alterar seu codigo para

def editar
end

Ao acessar a pagina esta ira redirecionar para o arquivo “app\views\produto\editar.rhtml”

Notem que não foi feita configuração em nenhum arquivo ainda. O fluxo de camadas é executado sguindo alguns padrões de nomenclatura.

9 - Realizando o CRUD. Como tudo ja esta funcionando vamos criar uma tabela de testes em todos os ambientes descritos no arquivo config/database.yml (hellorails_development , hellorails_test , hellorails_production).


CREATE TABLE PRODUTOS
(
id INTEGER NOT NULL PRIMARY KEY,
descricao VARCHAR(50) NOT NULL,
detalhes VARCHAR(255) NOT NULL,
preco DECIMAL(10,2) NULL
);

ALTER TABLE PRODUTOS MODIFY COLUMN `id` INTEGER NOT NULL DEFAULT NULL AUTO_INCREMENT;

Repare que a tabela foi criada no plural. O Rails vai fazer a co-relação de singular/plural.

Um recurso interessante é o scaffolding. Para utiliza-lo basta alterar o seu arquivo controller.


class ProdutoController < ApplicationController

scaffold :produto

end

Este é um recurso que mapeia as operações CRUD para esta determinada tabela. O interessante é que não há geração de código, portanto se for incluido um novo campo na tabela a tela será alterada também.

10 - Uma coisa que você deve estar questionando é quanto a customização. As telas criadas seguem templates do Rails, e com certeza em seus projetos você ira utilizar um padrão diferente. O Rails tem essa ideia de havendo necessidade de mudança é so você descrevê-las.

produto_controller.rb
class ProdutoController < ApplicationController

scaffold :produto

layout "default"

def list
@entries = Produto.find_all nil, "descricao"
end

def edit
@entry = Produto.find(@params["id"])
end

end

list.rhtml
<table border="1" cellpadding="4" cellspacing="0" width="90%">
<tr>
<th>Descricao</th>
<th>Preco</th>
<th colspan="3">Actions</th>
</tr>
<% @entries.each do |entry| %>
<tr>
<td><%= entry.descricao %></td>
<td><%= entry.preco %></td>
<td><%= link_to "Show", :action => "show", :id => entry.id %></td>
<td><%= link_to "Edit", :action => "edit", :id => entry.id %></td>
<td><%= link_to "Destroy", :action => "destroy", :id => entry.id %></td>
</tr>
<% end %>
</table
<p><%= link_to "New", :action => "new" %></p>

edit.rhtml
<%= start_form_tag :action => "update" %>

<%= hidden_field 'entry', 'id' %>

<p>Descricao:<br / ><%= text_field 'entry', 'descricao' %></p>
<p>Preco:<br / ><%= text_field 'entry', 'preco' %></p>
<p>Detalhes:<br / ><%= text_area 'entry', 'detalhes', "rows" => "3" %></p>

<input type="submit" value="Update" />

<%= end_form_tag %>

Java Hildebrando em 04 Nov 2006

Desenvolvimento de Aplicativos para dispositivos móveis.

A ideia de desenvolver um aplicativo para um celular ou PDA envolve um plano diferente. Parece que você esta entrando em um seleto grupo de profissionais, aquela força tarefa que faz as coisas acontecerem. Você esta saindo do arroz com feijão WEB-Struts-Hibernate (Arroz-com-feijão bem servido por sinal).

Na semana passada fiz um mentoring para uma grande empresa integradora de telefonia, e como havia muita comparação entre tecnologias, quero compartilhar algumas ideias.

Primeiramente vou tratar neste artigo da tecnologia J2ME (Java Micro Edition). Apresentar alguns pontos e após você estar craque vamos aos obstáculos.

1 - Inicio

Java você ja sabe, então precisamos aplicar este conhecimento em APIs diferentes. A boa notícia é que as specs para trabalhar com J2ME são simples. Pense que para programar para um celular os seus recursos são limitados e portanto o que diferencia é a forma como você deve utiliza-las.

Existem muitas ferramentas com plugins para tratamento deste mercado móvel. Vamos fugir delas, por enquanto.

Comece baixando o WTK da Sun - Sun Java Wireless Toolkit 2.2. A Sun possue um Kit (gratuito) para desenvolvimento de J2ME. A maioria dos fabricantes possue o seu, com a vantagem da utilização de emuladores do próprio. Porém isso não afeta em nada o seu software, apenas pode deixar voce mais confortavel em determinados trabalhos. Obrigatório porém se o que você procura é utilizar as APIs proprietárias.

A instalação é muito simples. Famoso Next,Next,Finish.

2 - Código

O WTK é um empacotador de projetos, ou seja, ele não é um editor/compilador. Sua unica tarefa é criar o seu projeto, organizando seus arquivos em pastas específicas e construção do pacote para deploy. Para completar ele possue alguns emuladores para você testar seu código.

Comece criando seu projeto no WTK.

a) Execute o Ktoolbar
b) New Project [Project Name : WhereIsWally][MIDlet Name : WhereIsWally]
c) Mude em ‘Configurations’ para CLDC 1.1

Seu diretorio de trabalho será:

\WTK22\apps\WhereIsWally\src

Todo aplicativo que você for desenvolver deve seguir um contrato de código. Este contrato é estabelecido pela classe abstrata javax.microedition.midlet.MIDlet. Por tanto abra o seu editor Java favorito e construa esta classe.


public class WhereIsWally extends MIDlet {
}

A ideia de você estender da classe MIDlet é tanto para herdar alguns metodos quanto para definir outros.


import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

public class WhereIsWally extends MIDlet {
public void startApp() {
}

public void pauseApp() {
}

public void destroyApp(boolean unconditional) {
}
}

Ao digitar este codigo lembre-se de adicionar no classpath do seu editor ou do sistema os jars midpapi20.jar e cldcapi11.jar. Ambos estão no diretorio lib, dentro do diretorio de instalação do WTK.

Os metodos apresentados acima são chamados de métodos de ciclo de vida e como o nome de cada um ja descreve são invocados a cada mudança de estado. Portanto lembre-se quem chama estes métodos é o Dispositivo móvel, e não o seu código.

Assim toda vez que o MIDlet for inicializado, o método startApp sera invocado, por exemplo.

3 - Código Usual

Para prosseguirmos com o processo de aprendizado você deve rechear os métodos com chamadas a API JME. E é somente estas APIS que podem ser utilizadas. Lembre-se que você esta desenvolvendo não mais com JSE, portanto algumas funcionalidades foram retiradas. A classe String por exemplo perdeu muitos dos seus métodos, a classe Math também, o pacote io mais ainda, as bibliotecas graficas AWT e SWING não existem. E muitas outras coisas.

Portanto para você saber o que você pode utilizar veja a documentação referente ao CLDC - JSR139. Imagine esse CLDC como o conjunto de classes fundamentais.

Porém só o CLDC não vai te levar a muito lugar não. Você precisa utilizar de recursos mais funcionais como acesso a chamadas HTTP por exemplo, ou utilização de sons e animações. Para isso voce deve conhecer o Profile MIDP - JSR118. Pense em Profile como recursos adicionais a parte core.

As APIs são curtas no entanto com um certo grau de complexidade (senão não existiram cursos de JME). Para impressionar seus amigos faça um programa bem básico.


import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

public class WhereIsWally extends MIDlet {
public void startApp() {
Alert alert = new Alert("Titulo","Texto no Alerta",null,AlertType.INFO);
Display.getDisplay(this).setCurrent(alert);
}

public void pauseApp() {
}

public void destroyApp(boolean unconditional) {
}
}

WTK >> Build >> Run

Esse é o HelloWorld. As APIS são simples, e bem organizadas. Seguindo sua estrutura hierárquica da para entender bem o que pode se colocar na tela ou não.

4 - High-level

Em JME existe a categoria de componentes de alto nível como o Alert, utilizado no exemplo anterior. A principal caracterítica deles é a facilidade na utilização, porém com isso é sacrificado a parte de customização, que pode ser essencial em alguns projetos. Existem outro componentes como o TextBox, List e o Form que também estão na mesma categoria. O principio da utilização deles é o mesmo. Instanciar um objeto e chamar o Display.getDisplay(this).setCurrente(objeto_criado).

O Form é o mais utilizado pois este possibilita agregar outros componentes dentro dele. Todos os filhos de Item. Assim montando uma tela com vários componentes.

5 - Low-level

E se você quiser criar uma tela de Splash ou um botão customizado ou mesmo um gráfico? Para isso você precisa conhecer os componentes de low-level, ou seja, aqueles que você vai desenhar, tratar eventos de tecla e tudo mais. Na AWT existe um objeto com essa funcionalidade. É o Canvas. Então no desenvolvimetno JME ele esta de volta, porém com algumas limitações, mas seguindo o mesmo modelo de desenhar utilizando o objeto Graphics (drawString, fillRect, etc).

6 - Jogos

Os jogos ganharam o pacote javax.microedition.lcdui.game (MIDP 2.0). Use e abuse deste pacote pois ele contem inumeras vantagens sobre o canvas no que se refere a parte de buferização para atualização da tela, essencial em jogos para garantir o dinamismo.

7 - Eventos

O tratamento de eventos é diferente para High-level, low-level e games. Para os de alto nível você precisa criar Listeners, parecido com o padrão AWT/Swing. Para os de low-level voce captura as teclas sobreescrevendo métodos específicos por ação como keyPressed. Para os games o tratamento é um pouco diferente pois obriga a verificação se o botão foi apertado através do start() de uma Thread. Esta garante a velocidade do jogo também.

8 - GCF

Generic Connection Framework é o comunicador com qualquer coisa. Se você quer abrir um Socket, enviar uma requisição HTTP ou enviar um SMS é através deste conjunto de classes que você vai conseguir. Pela especificação somente HTTP e HTTPS são mandatórios no MIDP 2.0, portanto você deve verificar se o dispositivo suporta as outras formas.

9 - Fim

Agora que você ja conhece boa parte da API e algumas funcionalidades vamos adiantar algumas restrições.

1 - Componente de High-level é de alto-nível mesmo. Se você não achar o método que o customize, esqueça. Quem o implementa é o dispositivo, assim se você manda abrir um Alert, este sera apresentado de acordo com o Alert do dispositivo.

2 - Para customizar um componente de High-level tente antes criar um com o CustomItem. Somente se não tiver possibilidade de adapta-lo baixe o nível para Canvas.

3 - A implantação em um celular envolve a geração de 2 arquivos, um JAR e um JAD. o JAD é um arquivo texto com um conjunto de pares chave/valor que descrevem sua aplicação, o arquivo JAR contem as suas classes compactadas. Para fazer a atualização do aplicativo no dispositivo utilize sempre o AMS (Gerenciador de Aplicações) pois nele podem ser configuradas regras de segurança. Para protegere seu codigo procure utilizar ofuscadores. Estes conseguirão embaralhar o codigo de forma que se alguem descompilar o seu JAR perderá muito tempo para entender seu algoritmo.

4 - Recurso vale ouro. Procure sempre declarar tipos pequenos como byte e short. Procure desenvolver regras de reutilização de objetos.