Olá à todos.
Em Android, Alarmes e Broadcast Receivers caminham junto. Por isso, veremos ambos os
tópicos de forma conjunta.
A classe AlarmManager
fornece acesso aos serviços de alarme do sistema. Estes permitem que você
programe seu aplicativo para ser executado em algum momento no futuro. Quando o
alarme dispara, a Intent que havia
sido registrada por este é transmitido pelo sistema, iniciando automaticamente
o aplicativo de destino se ele não estiver em execução. Alarmes registrados são
mantidos no sistema enquanto o dispositivo está dormindo (e pode,
opcionalmente, acordar o dispositivo durante esse tempo), mas serão apagados se
ele for desligado e reiniciado.
O AlarmManager
mantém o alarme na CPU enquanto o método onReceive()
(de um Broadcast Receiver) estiver em
execução. Isso garante que o telefone não durma até que seja finalizada a transmissão
do alarme. Uma vez que o onReceive()
retorne, o AlarmManager liberará o
alarme da CPU. Isso significa que seu telefone irá dormir em alguns casos (assim
que o seu método onReceive() completar).
Já um Broadcast
Receiver simplesmente responde à mensagens transmitidas por outros
aplicativos ou do próprio sistema. Estas mensagens são por vezes chamadas
eventos ou Intent’s. Um Broadcast Receiver é um componente em Android
que permite interagirmos com os eventos do sistema ou da aplicação. Todos os Receivers inscritos para um evento serão
notificados pelo Android uma vez este evento aconteça.
Exemplo de Alarme com Broadcast Receiver
Em nosso primeiro exemplo, criaremos um exemplo
simples de alarme em que uma Activity
interage com um Broadcast Receiver.
Nele, primeiramente, chamaremos um alarme 5
segundos depois da Activity ser
chamada. E, por fim, o faremos repetir a cada 10 segundos.
Antes de mais nada, precisamos definir nosso Broadcast Receiver no AndroidManifest.xml.
Podemos notar acima que o Broadcast Receiver foi definido através de um IntentFilter. Esta é outra maneira de se declarar um componente (Activity, Service, Broadcast Receiver)
no AndroidManifest.xml. Como isto é
chamado, veremos ao longo deste exemplo.
A Activity
que chama nosso alarme é mostrada abaixo.
No método onCreate()
é chamado o método schedule(). Neste
método, inicialmente, colocamos o IntentFilter
“EXECUTE_ALARM” dentro de uma PendingIntent.
Depois, inicializamos a hora em que o alarme será chamado, através do Calendar. E então, chamamos o alarme,
utilizando tanto a PendingIntent como
o Calendar. No caso do nosso exemplo,
o alarme será chamado 5 segundos depois que a Activity for inicializada.
Após estes 5 segundos, a PendingIntent será chamada. Ou seja, o fluxo do nosso aplicativo
irá para a classe AlarmReceiver (que
é o Broadcast Receiver associado com
o IntentFilter “EXECUTE_ALARM”).
A classe AlarmReceiver
é bem simples.
Ou seja, nesta classe tudo que fazemos é chamar
um Toast.
E pronto! Acabamos de criar nosso primeiro
exemplo de alarme em Android.
Agora, iremos fazer este alarme ser repetido a
cada 10 segundos. Para isto, criaremos uma classe chamada RepeatedAlarmActivity.
A principal diferença entre a RepeatedAlarmActivity e a SimpleAlarmActivity é o comando abaixo:
alarm.setRepeating(AlarmManager.RTC_WAKEUP,
time, REPEATING_TIME, p), que realiza a repetição do alarme, à cada 10 segundos.
De resto, a RepeatedAlarmActivity é praticamente
idêntica à SimpleAlarmActivity.
Agora, veremos um exemplo mais
complexo de alarme, em que utilizaremos, além das classes AlarmManager e BroadcastReceiver,
as classes Notification e Service.
Exemplo de alarme com Service e Broadcast Receiver usando RECEIVE_BOOT_COMPLETED
Neste exemplo, programaremos o alarme para ser
executado em uma hora específica. E para isto, precisamos assegurar que o
alarme será executado mesmo que o celular seja reiniciado.
Para isto, precisamos modificar nosso Broadcast Receiver para executar quando
o celular for ligado. Isto pode ser feito através do IntentFilter BOOT_COMPLETED. Além deste IntentFilter, precisamos declarar uma permissão específica. Ambos
são mostrados abaixo.
Como podemos notar pelo AndroidManifest.xml, temos neste exemplo duas Activity, um Service e um
Broadcast Receiver, e este funciona
tanto quando nosso aplicativo estiver sendo executado, quando o celular for
reiniciado.
Porém, se ele for executado quando o BOOT do
sistema for realizado, não poderemos utilizar logs de Logcat, e tampouco debugar a aplicação,
uma vez que ao ser reinicializado, o sistema fecha todas as aplicações que
estavam abertas antes de seu desligamento.
Por este motivo, neste exemplo, utilizaremos o
conceito ensinado no Capítulo 11
para criar “logs” em arquivos de texto dentro de nosso dispositivo Android.
Logo, neste aplicativo, utilizaremos a classe FileUtils (tal qual demonstrado no Capítulo 11) para salvar dados de log
em um arquivo localizado em nosso dispositivo Android. Esta classe será chamada
diretamente pela classe LogUtils, que
é mostrada abaixo.
Ou seja, nesta classe, tudo que faremos será
imprimir uma mensagem em um arquivo.
Agora que temos assegurado nosso log, podemos
executar a lógica que chamará o alarme.
Como pudemos ver no AndroidManifest.xml, neste exemplo temos duas Activity, um Service e um
Broadcast Receiver. A lógica que
usaremos será análoga ao primeiro exemplo de alarme, ensinado na seção anterior deste Blog. Ou seja, na tela principal
chamaremos um Broadcast Receiver.
No exemplo anterior, o chamávamos através de um
IntentFilter chamado EXECUTE_ALARM,
colocado em uma Intent que era
anexada à um PendingIntent. Neste
exemplo, o chamaremos através do próprio nome do Broadcast Receiver, que é PushNotificationReceiver.
Abaixo podemos ver como este Receiver é chamado na tela principal.
Após ser chamado, este Receiver executará primeiramente o método onReceive(). Como podemos ver abaixo, ele recebe um contexto (pois Receivers nativamente não possuem
contexto), e chamar o método schedule().
É no método schedule()
que chamamos o Service, colocando-o
em uma chamada de Intent, e colocando
esta em uma PendingIntent. Neste
método, caso a PendingIntent não
tenha sido criada (ou seja, o alarme não tenha sido programado ainda), chamamos
o método setAlarm(). Caso ela tenha
sido, imprimimos em nosso log uma mensagem de alerta.
Um dos argumentos do método setAlarm() é um retorno do método getAlarmTime(). Neste método, obtemos o
horário ao qual programamos nosso alarme (que é definido no arquivo string.xml). E nele também realizamos a
comparação mais importante de todo o Receiver:
a atualização da variável currTime.
O if
deste Receiver atualiza o valor desta
variável usando a seguinte lógica: se o alarme não tocou no dia atual, não
entramos neste if. Porém, se o alarme
já tocou (ou seja, se a hora e minuto correntes forem maiores que a hora e o
minuto do alarme), atualizamos o currTime
para o dia de amanhã, pelo comando currTime
+= 24 * 60 * 60 * 1000. Estamos somando o tempo atual à 1000 milisegundos,
multiplicados por 60 segundos, multiplicados por 60 minutos, multiplicados por
24 horas (ou seja, estamos somando currTime
ao dia de amanhã, 24 horas posteriores ao momento atual).
Em seguida, setamos currTime na variável calendar,
e retornamos este valor em milissegundos.
Em sequência, temos a definição do método setAlarm().
Neste método, chamamos o AlarmManager através dos já inicializados pendingIntent e time (que
nada mais é do que o retorno do recém explicado getAlarmTime()).
E assim chegamos ao fim do nosso PushNotificationReceiver, que chama o PushNotificationService. Este Service será chamado apenas quando
chegarmos EXATAMENTE ao horário
programado pelo AlarmManager. E como
definimos um Receiver em BOOT, mesmo
que o celular seja reiniciado, o Service
será chamado.
Então,vamos à implementação do Service:
Podemos notar acima que temos três constantes:
- NOTIFICATION_INTENT → É uma String que define um IntentFilter (tal qual esta definido em nosso AndroidManifest.xml). Neste caso, define a tela NotificationActivity.java.
- FROM_NOTIFICATION_EXTRA_KEY → Identificador de um Extra de Intent que enviaremos à tela NotificationActivity, com o intuito de cancelar a notificação chamada pelo Service.
- NOTIFICATION_ID → Identificador da nossa notificação. É o dado que será enviado juntamente com a FROM_NOTIFICATION_EXTRA_KEY para a tela NotificationActivity.
Temos também um atributo que armanena uma
instância de FileUtils, ao qual
chamaremos a classe LogUtils.
Repare também que temos o evento onBind(). Este evento não tem muita
importância na implementação do nosso Service.
Acima podemos ver o método onCreate(), onde chamamos o método createNotification() (onde criamos a notificação); cancelamos as Intent anteriores; retransmitimos o
alarme para o dia de amanhã; e, por fim, finaliza a si mesmo.
Logo abaixo, temos o método createNotification(), que nada mais é do
que uma revisão do que foi explicado no Blog, neste tópico. Nele, criamos uma notificação que chama a Intent NotificationActivity.
E abaixo, temos o método que cancela alarmes
anteriores. Este método é chamado entre o método createNotification() e o comando sendBroadcast(new Intent(this, PushNotificationReceiver.class)). Ou
seja, neste exato momento (entre o método o comando descritos acima),
precisamos certificar que nenhum alarme está programado para ser tocado (uma
vez que precisamos programar um novo alarme). Após nos certificarmos disso, aí
sim podemos chamar o próximo alarme pelo método sendBroadcast().
Repare acima que a PendingIntent chamou o IntentFilter
NOTIFICATION_INTENT. Verificando nosso AndroidManifest.xml,
podemos notar que a classe associada à este IntentFilter
é a PushNotificationService. Ou seja,
estamos obtendo as PendingIntent
associadas ao nosso Service.
Por fim, vamos à implementação da tela NotificationActivity, que é a tela
chamada após o alarme ser tocado.
Acima podemos notar que chamamos o método cancelNotificationIfNeeded().
Basicamente é isto que faremos nesta tela. Uma vez que a classe PushNotificationService é executada, e a
notificação é mostrada, chamamos a tela atual via PendingIntent, e nela precisamos cancelar a notificação. Caso
contrário, ela será mostrada eternamente.
Acima podemos notar de que maneira a
notificação é cancelada: recebemos um Extra
de Intent do nosso Service (que nada mais é do que o id da
nossa notificação), e com ele, a cancelamos.
E isto é tudo! Já temos conhecimento para criar
um alarme executável em um horário específico, mesmo que para tal precisemos
reiniciar nosso celular.
-----
Caso alguém tenha uma dúvida, crítica ou sugestão, sinta-se à vontade.
Nenhum comentário:
Postar um comentário