terça-feira, 2 de agosto de 2011

Recuperando e Lendo Arquivos de um Cartão de Memória - PARTE 3

01. private final void tocarMusica(String dirArq)
02. {
03.     ProgressBar splash = new ProgressBar(this);
04.
05.     setContentView(splash, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
06.
07.     try
08.     {
09.         player.setDataSource(dirArq);
10.         player.prepare();
11.         player.setLooping(true);
12.         player.start();
13.     }
14.     catch (Exception e)
15.     {}
16. }

Seguiremos para o método que toca uma música, caso o arquivo escolhido na tela anterior esteja no formato sonoro.  A classe ProgressBar é novidade aqui. Sua finalidade original é servir de splash nas aplicações, informando o usuário sobre o andamento de um processo. Como achei sua animação bastante parecida com a de um tocador de músicas, resolvi apresentá-la na tela enquanto rola a faixa. Assim como aconteceu com ImageView, ProgressBar também irá ocupar a tela toda:

Objeto ProgressBar ocupando toda a tela
    As linhas 07-15 correspondem ao código que tocará a música. Antes de tudo, lembremos que player é uma instância de MediaPlayer(), que foi definida como global nesta classe. Mais adiante você entenderá por que não a declaramos localmente. 
    O método setDataSource(dirArq) diz ao player onde está o arquivo, que nada mais é que o diretório passado pela Activity inicial. O método prepare() avisa ao player que tudo está pronto para que a faixa seja tocada. Sempre chame este método antes de tocar a música. O método  setLooping(true) é opcional  e serve para reproduzir a música continuamente. Por fim, reproduzimos a música com start(). Por uma questão de simplicidade, não foi fornecido um tratamento adequado das possíveis exceções disparadas caso houvesse erro na reprodução da mídia.


REPRODUZINDO O VIDEO

01. private final void reproduzirVideo(String dirArq)
02. {
03.     VideoView video = new VideoView(this);
04.     video.setVideoPath(dirArq);
05.     video.setMediaController(new android.widget.MediaController(this));
06.     video.start();
07.
08.     setContentView(video);
09. }

A próxima parada será no método que reproduz um vídeo na tela. Embora seja possível fazê-lo com a classe MediaPlayer, usaremos uma específica pra isso.
Após criar um objeto de VideoView, nós lhe indicamos a localidade do arquivo de vídeo. O método setMediaController(MediaController controles) , embora opcional, é importante, pois insere abaixo do vídeo botões para reproduzi/pausar e avançar/retroceder o vídeo. Finalmente, chamamos start() para iniciar a reprodução, como ocorre com MediaPlayer().
VISUALIZANDO O TEXTO

01. private final void visualizarTexto(String dirArq)
02. {
03.     try
04.     {
05.         FileInputStream textoLeitura = new FileInputStream(new java.io.File(dirArq));
06.
07.         byte[] textoTemp = new byte[textoLeitura.available()];
08.
09.         try
10.         {
11.             int index = 0;
12.             int c = 0;
13.
14.             while((c = textoLeitura.read()) != -1)
15.             {
16.                 textoTemp[index++] = (byte)c;
17.             }
18.
19.             textoLeitura.close();
20.         }
21.         catch (Exception e)
22.         {
23.             e.printStackTrace();
24.         }
25.
26.         ByteArrayInputStream bais = new ByteArrayInputStream(textoTemp);
27.         DataInputStream dis = new DataInputStream(bais);
28.         char[] chars = new char[textoTemp.length];
29.
30.         try
31.         {
32.             int index = 0;
33.             int c = 0;
34.
35.             while((c = dis.read()) != -1)
36.             {
37.                 chars[index++] = (char)c;
38.             }
39.
40.             bais.close();
41.             dis.close();
42.         }
43.         catch (Exception e)
44.         {
45.             e.printStackTrace();
46.         }
47.
48.         TextView texto = new TextView(this);
49.         texto.setText(new String(chars));
50.
51.         LinearLayout layout = new LinearLayout(this);
52.         layout.addView(texto);
53.         ScrollView scroll = new ScrollView(this);
54.         scroll.addView(layout);
55.         setContentView(scroll);
56.     }
57.     catch (Exception e)
58.     {}
59. }

    O método que mostra o texto na tela merece maior atenção, principalmente por lidar com fluxos, parte melindrosa do Java.
    A primeira coisa a fazer é extrair do arquivo de texto seu conteúdo em forma de fluxo de bytes para entrada. A classe FileInputStream, filha de InputStream, é a indicada para extrair armazenar esse stream. Depois, precisaremos de um array de bytes que virá a armazenar esse fluxo.
    FileInputStream, através do método read(), tem o poder de ler dado por dado o fluxo que
armazena, retornando um valor inteiro que representa cada dado. Este inteiro, após ser 
convertido em byte, passará a ser armazenado pelo vetor de bytes, que nos interessará em
breve. Quando FileInputStream retornar -1, significa que chegou ao final de seu fluxo. É
importante fechá-lo depois com close(), fazendo que com que seus recursos sejam liberados
da memória.
    Daqui, nós poderíamos saltar para a linha 48, passando para o construtor da String o array de bytes já alimentado. Conseguiríamos exibir o texto? Sim. No entanto, se esse texto contiver caracteres acentuados, esse será o resultado:

Leitura imprecisa de um arquivo de texto
    
    Para evitar isso, faremos uso das classes ByteArrayInputStream e DataInputStream. Funciona assim: ByteArrayInputStream recebe em seu construtor o array de bytes criado anteriormente. Depois, instanciamos um DataInputStream, utilizada para ler tipos específicos de dados a partir de  um fluxo de bytes, tais como booleanos, strings e caracteres. Ela recebe no construtor a referência a ByteArrayInputStream, da qual lerá o texto. O método de leitura é idêntico ao loop anterior e também é necessário liberar os recursosde cada um com close().
    Agora temos um array de caracteres acentuados que compõe o texto que será exibido. Ocomponente TextView(), apresentado agora, é muito útil para exibir texto na tela. Depois de instanciá-lo, configure o texto que ele irá mostrar com o método setText()dando-lhe o array de caracteres que acabou de encontrar.
    Desta vez, ao invés de exibir o View diretamente, adicionaremos ele a um LinearLayout().  Essa classe atua como um contêiner que, além de abrigar componentes, controla como estes serão exibidos.
    Você deve ter se perguntado o que acontecerá se a tela não for grande o bastante para
abrigar o texto. Felizmente podemos contar com a famosa barra de rolagem, representadano Android pela classe ScrollView. Uma vez criada, você pode adicionar a ela um View, seja ele um componente ou um layout. Como o TextView que exibirá o texto está dentro de umLinear Layout, nós usaremos o método add(View view) para adicionar o layout ao ScrollView. Finalmente, o método setContentView(View view) recebe a instância de ScrollView, que guarda LinearLayout, que por sua vez guarda o TextView. Eis como o texto será apresentado desta vez:

Leitura correta de um arquivo de texto
   
A prática comum é que se escreva a interface gráfica das aplicações em arquivos XML à
parte, tornando o código Java mais limpo e permitindo uma separação lógica entre o visual e o comportamento da aplicação. Porém, haverá situações em que é mais conveniente criar o layout da aplicação dinamicamente, isto é, com puro Java. 

FINALIZANDO A ACTIVITY

01. @Override
02. protected final void onDestroy()
03. {
04.     if(formato == MUSICA)
05.     {
06.         player.release();
07.     }
08.
09.     super.onDestroy();
10. }

    Chamaremos a atenção para o método onDestroy(). Ele faz parte do ciclo de vida de uma Activity, sendo chamado implicitamente quando uma Activity é finalizada ou quando o provocamos através de finish(). A razão de termos sobrescrito esse método aqui é para liberar os recursos alocados pelo player de música, caso a Activity tenha sido invocada para reproduzir uma música. Assim como ocorre com fluxos e conexões, você precisa de um método próprio pra liberar os recursos alocados. Neste caso você chama release().


Dados.Java

INTERFACE COMO REPOSITÓRIO DE CONSTANTES

01. public interface Dados
02. {
03.     static final int MUSICA = 0;
04.     static final int VIDEO = 1;
05.     static final int IMAGEM = 2;
06.     static final int TEXTO = 3;
07. }

Um uso pouco comum para uma interface é usá-la como repositório de constantes que são
compartilhadas por diferentes classes da aplicação. Embora quatro constantes possam não ser uma desculpa para armazená-las em uma interface, pode haver situações em que diversas classes irão ter em comum um grande número de constantes, como em um game, tipo de app mais popular atualmente para Android. Há alguns meses, desenvolvendo meu primeiro game em J2ME (confira video no final do artigo), tinha em mãos oito classes que compartilhavam um bom número de constantes, que envolviam desde estados do game e dos inimigos até dimensões de imagens. Ao organizar quase cem constantes em uma única interface, além de tornar as outras classes  mais legíveis, boa parte do código passou a ter uma manutenabilidade centralizada.


4 comentários:

ADMIN-BLOG disse...

Bom dia, amigo
Gostei do seu tutorial, mas como sou leigo ainda em android (java), tem como vc postar o link do projeto, ou mandar via email para eu poder entender melhor.

Parabéns

Marcelo
marcelo@cootrade.com.br

Unknown disse...

Boa noite,
tentei usar seu tutorial para rodar o exemplo mais não deu muito certo deu alguns erros ao executar.
Você poderia me mandar o código por e-mail.
Desde já agradeço.

Gislaine
gigisalvatico@hotmail.com

Andrew disse...

Poderia me mandar também o link do projeto?

Andrew
hideki.andrew@hotmmail.com

Muito obrigado.

Claudecir Miranda disse...

Muito bom o post!

Se tivesse o código para nos guiar seria mais fácil o entendimento.

Você poderia postá-lo.

Postar um comentário