terça-feira, 26 de março de 2013

Livro do Lecheta, Google Android, 3ª edição revisada e ampliada


Dei uma verificada rápida nas diferenças de conteúdo da nova edição (3ª) do livro Google Android do Ricardo Lecheta com a edição anterior.

Inclusão dos tópicos:
    Fragments
    Thread
    AsyncTask

Alteração (significativa) capítulo:
    Mapas e GPS, uso da API v2

Inclusão dos capítulos:
    GCM - Google Cloud Messaging
    Reconhecimento de gestos
    Sensores
    Bluetooth
    Text-to-speech, Speech-to-text
    NDK

O livro cresceu mais de 200 páginas.

A conferir.
Abraços

segunda-feira, 25 de março de 2013

Livro indicado

Acabo de ser informado sobre o lançamento da 3ª edição do livro Google Android
Revisado, atualizado e ampliado
Autor: Ricardo Lecheta

sexta-feira, 22 de março de 2013

Conceitos de programação concorrente no Android

  Programação concorrente é uma área em que me interesso muito, tenho dedicado bastante tempo estudando o assunto. Pode ser considerado como uns dos tópicos mais difíceis de aprender.
  Vou postar o que (eu acho que) aprendi sobre o tema.

  Para ficar mais interessante vou tentar fazer um paralelo com a vida (quase) real.
  Imaginem um estudante de programação de computadores que resolve abrir uma empresa, empresa de desenvolvimento de sistemas, é claro.
  O foco é desenvolver aplicações para dispositivos móveis, para Android, é claro, novamente!
  No começo, é uma empresa de um homem só. Como o seu nível de conhecimento em programação Java é apenas um pouco além do básico, o destemido desenvolvedor foca um nicho de mercado de pequenos utilitários. Com poucas telas e de programação mais simples.
  Mas, com o tempo, com muito esforço e sorte, acaba recebendo algumas encomendas mais sofisticadas, algumas até com conexão à internet.
  O aplicativo funcionava muito bem, mas, tem sempre um mas... Pediram uma versão para tablet, última geração, multi-core, Android 4...
  Quando foi testar, recebeu uma mensagem estranha: "android.os.NetworkOnMainThreadException".
Foi dar uma pesquisada no Google e encontrou a explicação: a partir do Honeycomb, uma tentativa de executar uma conexão à internet estando na Main Thread vai receber esse erro.
  Como já tinha interesse em aprender programação concorrente, resolveu estudar o assunto mais a fundo. Logo, encontrou um amigo que se dispôs a ensinar...

  Para encurtar a estória, teve que contratar uma ajudante-geral, para atender os clientes enquanto estava fora.

  Logo na primeira aula, ficou sabendo que em Java a classe que permite fazer processamento concorrente é a classe Thread. Ao instanciar um objeto thread, e dar start, uma linha de execução paralela é iniciada para processar a tarefa.
  O desenvolvedor notou, que isso era semelhante ao passar uma tarefa para a ajudante, ele podia imediatamente fazer outras coisas enquanto ela, em paralelo, executava a tarefa.
  Verificou também que para saber se a thread já tinha terminado, tinha algumas opções, como checar de tempo em tempo o status dela ou fazer a própria thread avisar quando terminasse o serviço. Assim, como fazia com a ajudante. Apenas, que ela não era tão educada quando era interrompida! Ela sempre dizia: quando eu terminar eu aviso!

  Às vezes ele passava uma tarefa para a ajudante e ficava esperando ela terminar sem fazer nada, tal qual o programa quando usava um myThread.join()...

  Em outra aula, aprendeu sobre exclusão-mútua. A necessidade de executar um pedaço do código de maneira exclusiva, ou seja, uma thread por vez.
  Esse tipo de necessidade, na empresa, ele teve com o uso do lavatório. Quando era apenas ele, trancar a porta do lavatório só quando tinha visita... Com a entrada da ajudante, tiveram que estabelecer certas regras de convívio, quem tinha a posse da chave, tinha a exclusividade do lavatório. Assim, muitos constrangimentos foram evitados...
  No programa, também, quem tem a posse da trava tem acesso exclusivo a um trecho de código. Assim, muitos erros são evitados.

  No caso da visibilidade, as coisas são opostas, na empresa, quem tem a chave tem onde se esconder, no programa quem tem a chave (quero dizer, a trava) tem acesso às variáveis compartilhadas!

  Quando estava estudando sobre problemas de compartilhamento de variáveis e a obrigatoriedade de usar uma mesma trava, pensou, como seria embaraçoso tentar implementar o uso de duas chaves para usar o lavatório...

  Na última sessão de estudos, o assunto foi a classe AsyncTask, verificou que uma tarefa pode ser dividida em subtarefas quando essas subtarefas precisam ser executadas em threads diferentes em momentos diferentes.
Da mesma forma, como na empresa,  assinar um documento é responsabilidade do desenvolvedor, mas preencher pode ser executado pela ajudante.
Assim, acessar o servidor deve ser feito em outra thread, mas, atualizar a tela é responsabilidade da Main Thread.

Abraços

sábado, 16 de março de 2013

Estratégia para Encerramento de Threads


  A grande maioria das threads que usamos deixamos encerrar naturalmente ao encerrar a tarefa que estamos executando. Ou seja, ao encerrarmos o Runnable a thread encerra também.
  Mas, existem alguns casos em que uma thread tem uma duração infinita. Digo, no sentido "infinito enquanto dure" do Vinicius de Moraes...
  No Java não temos uma maneira direta de encerrar uma thread. Temos de solicitar o encerramento da thread via um "recado".
  Uma forma é usar uma variável booleana para indicar a intenção de que desejamos encerrar o processo em execução.
  Deve-se definir essa variável como volatile ou sincronizar os acessos a ela, senão o "recado" pode não chegar à thread destinatária.
  Mas, essa forma não resolve todos os casos, se a tarefa estiver bloqueada por algum motivo, e se não sair do bloqueio, não verá o pedido de encerramento.
  Para esses casos, temos a opção de usarmos o método da thread chamado interrupt(). Esse método liga uma variável de status da thread que indica que foi solicitado uma interrupção. Aí é só verificar essa variável com o método isInterrupted() para saber se o encerramento foi solicitado, ou, se estiver bloqueado por algum método que responda a interrupção, vai receber um InterruptedException.
  O importante é que precisamos definir uma estratégia de encerramento para as threads. Devemos definir claramente, como solicitar o encerramento, quando a tarefa deve verificar se foi solicitado o encerramento e, finalmente, quais procedimentos realizar para encerrar a tarefa.

Isso é fundamental no Android, senão, podemos ter threads "trabalhando" mesmo com a app em background.

PS1: Temos alguns casos em que o recurso que está bloqueando não responde à interrupção, nesses casos, devemos usar uma tática diferente para cada caso, mas, como regra geral, fechamos/encerramos o recurso, o que acarretará em alguma Exception.

PS2: Se estiver bloqueado por trava, só vai avançar se obtiver a trava.

PS3: Se estiver usando AsyncTask, usar cancel() para solicitar o encerramento e no doInBackground() verificar se foi solicitado o encerramento via isCanceled().

PS final: Se você usa uma outra estratégia, posta aqui para termos outra abordagem!


Abraços




domingo, 10 de março de 2013

Estudando Design Patterns

Plano de estudos para o primeiro trimestre: Design Patterns.

Materiais:


.Apostila - Design Patterns em Java, da K19

.Livro - Design Patterns: Elements of Reusable Object-Oriented Software
             Erich Gamma, Richard Helm, Ralph Johnson e John Vlissides

.Livro - Head First Design Patterns
             Eric Freeman, Elisabeth Robson, Bert Bates e Kathy Sierra


Abraços

quarta-feira, 6 de março de 2013

Cuidados em relação ao uso de Threads


Estive dando uma boa estudada em threads e registrei algumas observações que acho útil deixar aqui no blog, pode ser de interesse para quem também esteja estudando o tópico.

Tenho dito que usar threads é imperativo no Android, quem já tomou um "ANR" ou mais recentemente, "NetworkOnMainThreadException", sabe do que estou falando.
Já postei também sobre os diversos benefícios advindos do uso de threads em aplicativos Android.

Mas, tem o outro lado da questão: os riscos no uso de threads.
Primeiro temos os riscos de segurança, relacionados com o uso compartilhado de dados, principalmente dados mutáveis, e seu gerenciamento, podemos resumir esses problemas como "acesso em momento indevido", seja por acesso a um objeto em fase de construção, ou no meio de uma atualização, ou atomicidade, ou problemas de visibilidade.
Por visibilidade entendam: uma thread pode não "ver" as últimas alterações que outra thread tenha feito num determinado dado.
Depois temos os problemas relacionados com ativação de threads, seja travamento por deadlock, ou threads que não conseguem avançar por falta de recursos.
E, por fim, temos os problemas de performance, afinal, ter uma outra thread tem um custo, que não está relacionado com processamento produtivo e sim em gerenciar as diversas threads.

Usar threads com eficiência significa tentar usar o máximo de processamento paralelo e o mínimo de processamento sequencial. Identificar quando o processamento deve ser sequencial, é responsabilidade do programador, então, o DVM (Dalvik Virtual Machine) espera (e todos os seus usuários, sem contar o seu chefe e outros interessados...) que você tenha informado corretamente esses pontos de sincronismo.
Isso, sincronização, deve ser feito para garantir consistência sequencial.
Você precisa ter ciência de que o compilador, o Dalvik, o Sistema Operacional e o processador todos estão fazendo malabarismos com o seu código para obter o máximo de performance possível.
Então saiba usar nos lugares certos as palavras chaves synchronized, volatile, lock, unlock, wait, notify, etc, senão o seu programa vai fazer coisas difíceis de imaginar, imagine como conseguir corrigir!

Bons códigos!