segunda-feira, 30 de abril de 2012

Executando tarefas sequencialmente em outra Thread no Android

 Este post exemplifica uma necessidade que às vezes ocorre em um projeto: executar uma série de tarefas sequencialmente em uma thread.
 Para fazer isso temos um recurso em Java que atende perfeitamente ao requisito acima: a estrutura Executor. Um executor é basicamente um gerenciador de threads e tarefas.
 O exemplo consiste em executar uma série de tarefas numa única thread que é controlada por um executor. A tarefa vai ser representada por uma classe que vai implementar um Runnable (MyTask). Para não ficar invisível vamos atualizar a tela com o Dialog.
 Vamos também usar uma outra thread para definir o Executor e submeter as tarefas para execução e aguardar até o fim de todas as tarefas para encerrar o Dialog ( MyControlThread).

 Os códigos:
 TesteExecutorsActivity.java


main.xml



Manifest file


PS: Algumas considerações sobre o código: No trecho abaixo, devemos observar o seguinte:
 a. O executor é definido com uma thread para podermos executar as tarefas sequencialmente uma a uma.
b. O loop for é para simular a submissão de "n" tarefas, normalmente teríamos diversas tarefas diferentes sendo submetidas da seguinte forma:
PS1: Nas tarefas, o Handler é utilizado para executar algum código na UI Thread, normalmente para alterar a tela.

 Executando no emulador:


sábado, 28 de abril de 2012

Um ano de Java


Estou completando um ano de convívio diário com a linguagem Java.
É muito pouco tempo para ter um domínio de um ambiente muito complexo de programação.
Por outro lado, minha capacidade de aprender coisas novas tem diminuído com o passar do tempo. É a idade cobrando o seu tributo.
Soma-se a isso o aprendizado do Android.
Muito mais conhecimentos a dominar.
Estou usando uma técnica de aprendizado incremental.
Funciona assim:
Defino uma lista de assuntos a estudar.
Estudo o básico sobre cada assunto.
Revejo a lista de assuntos, eliminando ou acrescentando novos itens.
Estudo novamente cada assunto, desta vez acrescentando mais profundidade em cada tema estudado.
Tenho repetido esses ciclos por diversas vezes, e tem dado um bom resultado para mim.
A vantagem disso é que como sei que vou voltar ao assunto, se ele estiver muito díficil ou incompreensível para mim naquele momento eu não gasto muito tempo nem energia com ele, sigo em frente. No próximo ciclo de estudos, terei agregado experiência e novos conhecimentos para entendê-lo.
Até recentemente, estive focado no estudo do Java básico e no Android até o 2.x.
Agora estou tentando me aprofundar em processamento concorrente em Java e começando a estudar o Android 3.x para frente.

Abraços!

quinta-feira, 5 de abril de 2012

Java, valores monetários: float, double e BigDecimal

Quando estamos trabalhando com valores monetários, os tipos float e double não são adequados devido aos problemas de precisão. Nem todas as frações tem representação exata nestes dois tipos de dados. Para ver isso na prática, basta fazer o seguinte teste:



Altere para float e teste. E terá algo assim: saida = soma 10.000002.

Quando estamos trabalhando com valores monetários precisamos definir as seguintes regras de negócio:
 1. Escala - número de casas decimais após a vírgula.
 2. Arredondamento - como vamos tratar os valores após a escala definida em 1.
 3. Quando arredondar - em que momento vamos fazer o arredondamento.

 Para definir essas regras, temos que verificar diversas leis ou normas: fiscais, bancárias, contábeis, legais, etc.

 Como float e double não servem temos duas alternativas: ou usar inteiros e controlar o número decimais por conta própria ou usar a classe BigDecimal.

 Vamos ver a classe BigDecimal.

 Para definir: BigDecimal bd = new BigDecimal("1.01");
                      BigDecimal bd2 = new BigDecimal("2.00");
 Para somar: bd = bd.add(bd2);
 Para subtrair: bd = bd.subtract(bd2);
 Para multiplicar: bd = bd.multiply(bd2);
 Para dividir: bd = bd.divide(bd2, intScala, BigDecimal.ROUND_UP);

 Dicas:
   a. Definição
       Defina sempre a partir de uma string.
       Para converter de float use: Float.toString(meuFloat);
       Para converter de double use: Double.toString(meuDouble);
   b. Comparação
       Use os métodos: compareTo() ou signum() - retorna inteiro (-1 para menor, 0 para == e 1 para maior)
       Não use equals() - ele é sensitivo a escala, vai dar diferente se a escala for diferente, mesmo para números iguais.
   c. BigDecimal é um objeto imutável
       Então após cada operação ele retorna um novo objeto - não se esqueça de salvá-lo!

 O BigDecimal tem oito formas de arredondamento.
 Segue a lista. Está em inglês, em baixo eu tento decifrar e dou uns exemplos, sempre para a escala 2.

"ROUND_UP " Rounding mode to round away from zero.
        Arredonda para: o mais distante de zero, maior em valor absoluto
        Se valor negativo: arredonda para o menor valor
        Se valor positivo: arredonda para o maior valor
        -0.001 => -0.01
          0.001 => 0.01

"ROUND_DOWN " Rounding mode to round towards zero.
         Arredonda para: o mais próximo de zero, menor em valor absoluto
         Se valor negativo: arredonda para o maior valor
         Se valor positivo: arredonda para o menor valor
        -0.009 => 0.00
         0.009 => 0.00

"ROUND_CEILING " Rounding mode to round towards positive infinity.
       Arredonda para: o maior valor
      -0.001 => 0.00
       0.001 => 0.01

"ROUND_FLOOR " Rounding mode to round towards negative infinity.
      Arredonda para: o menor valor
     -0.001 => -0.01
      0.001 => 0.00

"ROUND_HALF_DOWN " Rounding mode to round towards "nearest neighbor" unless both neighbors are equidistant, in which case round down.
      Verifica o valor excedente: se diferente de 5, para o "vizinho mais próximo"
             se igual a 5 => para o valor absoluto menor
      -0.006 => -0.01
      -0.005 =>  0.00
      -0.004 =>  0.00
        0.004 => 0.00
        0.005 => 0.00
        0.006 => 0.01

"ROUND_HALF_UP " Rounding mode to round towards "nearest neighbor" unless both neighbors are equidistant, in which case round up.
      Verifica o valor excedente: se diferente de 5, para o "vizinho mais próximo"
            se igual a 5 => para o valor absoluto maior
      -0.006 => -0.01
      -0.005 => -0.01
      -0.004 => 0.00
       0.004 => 0.00
       0.005 => 0.01
       0.006 => 0.01

"ROUND_HALF_EVEN " Rounding mode to round towards the "nearest neighbor" unless both neighbors are equidistant, in which case, round towards the even neighbor.
      Verifica o valor excedente: se diferente de 5, para o "vizinho mais próximo"
          se igual a 5 => verifica o digito a ser arredondado
              se impar => arredonda para o maior em valor absoluto
              se par     => arredonda para o menor em valor absoluto
 Esse tipo de arredondamento é indicado para evitar distorção no resultado devido aos arredondamentos cumulativos na mesma direção. Um uso seria em estatísticas, onde um grande volume de dados são manipulados.
     -0.015 => -0.02
     -0.025 => -0.02
      0.015 => 0.02
      0.025 => 0.02

"ROUND_UNNECESSARY" Rounding mode to assert that the requested operation has an exact result, hence no rounding is necessary.
     Quando não tem arredondamento a ser efetuado. Se tiver ocorre um ArithmeticException.
    -0.01 => -0.01
     0.01 => 0.01
     0.011 => ArithmeticException

 BigDecimal bd = new BigDecimal("10.001");
 bd = bd.setScale(2, BigDecimal.ROUND_UP); // = 10.01

BigAbraços!