Alarmes (com base na classe AlarmManager ) oferecem uma maneira de executar operações baseadas em tempo fora do tempo de vida de sua aplicação. Por exemplo, você poderia usar um alarme para iniciar uma operação de longa duração, como iniciar um serviço uma vez por dia para baixar a previsão do tempo.
Os alarmes devem ter as seguintes características:
- Eles permitem disparar Intenções em datas fixas e / ou intervalos.
- Você pode usá-los em conjunto com receptores de radiodifusão para iniciar os serviços e executar outras operações.
- Eles operam fora da sua aplicação, de modo que você pode usá-los para acionar eventos ou ações, mesmo quando o aplicativo não está em execução, e mesmo se o próprio dispositivo está dormindo.
- Eles ajudam você a minimizar as necessidades de recursos do seu aplicativo. Você pode agendar operações sem depender de temporizadores ou continuamente em execução serviços em segundo plano.
Nota: Para as operações que são garantidos para ocorrer durante o tempo de vida de sua aplicação sincronismo, ao invés considerar o uso do Handler classe em conjunto com Timer e Thread . Esta abordagem dá Android melhor controle sobre os recursos do sistema.
Entenda o trade-offs
Um alarme de repetição é um mecanismo relativamente simples, com flexibilidade limitada. Pode não ser a melhor escolha para a sua aplicação, especialmente se você precisa para desencadear operações de rede. Um alarme de mal projetado pode causar o consumo da bateria e colocar uma carga significativa em servidores.
Um cenário comum para o desencadeamento de uma operação fora do tempo de vida de seu aplicativo é quando estiver sincronizando dados com um servidor. Este é um caso em que você pode ser tentado a usar um alarme de repetição. Mas se você possui o servidor que está hospedando os dados da aplicação, utilizar o Google Cloud Messaging (GCM) em conjunto com o adaptador de sincronização é uma solução melhor do que AlarmManager . Um adaptador de sincronização lhe dará as mesmas opções de agendamento como AlarmManager , mas oferecerá muito mais flexibilidade. Por exemplo, uma sincronização pode ser baseada em uma mensagem de "novos dados" a partir do servidor / dispositivo (pesquise Executando um Adaptador de sincronização para mais detalhes), a atividade do usuário (ou inatividade), a hora do dia, e assim por diante.
Melhores práticas
Cada escolha que você faz ao projetar seu alarme repetitivo pode ter consequências na forma como seu aplicativo usa (ou abusa) recursos do sistema. Por exemplo, imagine um aplicativo popular que se sincroniza com um servidor. Se a operação de sincronização é baseada na hora do relógio e cada instância do aplicativo sincroniza às 11:00, a carga sobre o servidor pode resultar em alta latência ou mesmo "negação de serviço". Siga estas melhores práticas na utilização de alarmes:
- Adicionar aleatoriedade para quaisquer solicitações de rede que provocam, como resultado de um alarme de repetição:
- Fazer qualquer trabalho local quando o alarme dispara. "O trabalho Local" significa qualquer coisa que não bate um servidor ou exigir os dados do servidor.
- Ao mesmo tempo, programar o alarme que contém os pedidos de rede para disparar contra um certo período de tempo aleatório.
- Mantenha a sua frequência de alarme a um mínimo.
- Não acorde o dispositivo desnecessariamente (este comportamento é determinado pelo tipo de alarme, conforme descrito em Escolha um tipo de alarme ).
- Não faça o tempo de disparo do seu alarme mais vezes do que tem que ser.
- Use setInexactRepeating() em vez de setRepeating() . Quando você usa setInexactRepeating() , o Android sincroniza repetir alarmes de vários aplicativos e dispara-os ao mesmo tempo. Isto reduz o número total de vezes que o sistema tem de ativar o dispositivo, reduzindo assim a drenagem da bateria. A partir do Android 4.4 (API Nível 19), todos os alarmes de repetição são inexatos. Observe que, enquanto setInexactRepeating() é uma melhoria em relação setRepeating() , ele ainda pode sobrecarregar um servidor se cada instância de um aplicativo atinge o servidor na mesma época. Portanto, para solicitações de rede, adicionar um pouco de aleatoriedade aos seus alarmes, como discutido acima.
- Evitar basear o seu alarme na hora do relógio, se possível. Alarmes repetitivos que são baseados em um tempo de disparo preciso não funcionam bem. Use ELAPSED_REALTIME se puder.
Definir um alarme repetitivo
Como descrito acima, alarmes de repetição são uma boa escolha para agendar eventos regulares ou pesquisas de dados. Um alarme de repetição tem as seguintes características:
- Um tipo de alarme. Para mais discussão, pesquise tipos de alarme .
- Um tempo de disparo. Se o tempo de disparo você especificar está no passado, o alarme dispara imediatamente.
- Intervalo do alarme. Por exemplo, uma vez por dia, a cada hora, a cada 5 segundos, e assim por diante.
- A intenção pendente (PendingIntent) que é acionada quando o alarme é disparado. Quando você define um segundo alarme que usa a mesma intenção pendente, ele substitui o alarme inicial.
Escolher um tipo de alarme
Uma das primeiras considerações na utilização de um alarme de repetição é o seu tipo deve ser.
Existem dois tipos de relógio gerais para alarmes: "o tempo decorrido real" e "relógio de tempo real" (RTC). tempo real decorrido utiliza o "tempo desde a inicialização do sistema", como uma referência, e relógio de tempo real utiliza UTC tempo (relógio de parede). Isto significa que o tempo real decorrido é adequado para a fixação de um alarme com base na passagem de tempo (por exemplo, um alarme que dispara a cada 30 segundos), uma vez que não é afectada pelo tempo de fuso / local. O tipo de relógio de tempo real é mais adequado para os alarmes que são dependentes da localidade atual.
Ambos os tipos têm uma versão "despertar", que diz para acordar a CPU do dispositivo se a tela está desligada. Isso garante que o alarme será acionado na hora programada. Isso é útil se o seu aplicativo tem um exemplo de dependência de tempo, se ele tem uma janela limitada para realizar uma operação particular. Se você não usar a versão de despertar do seu tipo de alarme, em seguida, todos os alarmes de repetição serão acionados quando o dispositivo está for acordado.
Se você simplesmente precisa o alarme para disparar em um intervalo específico (por exemplo, a cada meia hora), use um dos tipos de tempo real decorrido. Em geral, esta é a melhor escolha.
Se você precisar de seu alarme para disparar em um determinado momento do dia, em seguida, escolha um dos tipos de relógio de tempo real baseado em relógios. Note, no entanto, que esta abordagem pode ter alguns inconvenientes: o aplicativo pode não traduzem bem a outras localidades, e se o usuário altera configuração de tempo do dispositivo, que poderia causar um comportamento inesperado no seu aplicativo. Usando um tempo real tipo de relógio de alarme também não escala bem, como discutido acima. Recomendamos que você use um alarme "em tempo real decorrido", se puder.
Lista de tipos:
ELAPSED_REALTIME - Destrói a intenção pendente com base na quantidade de tempo desde que o dispositivo foi inicializado, mas sem acordar o dispositivo. O tempo decorrido inclui qualquer momento durante o qual o dispositivo foi adormecido.
ELAPSED_REALTIME_WAKEUP - Acorda o dispositivo e dispara a intenção em andamento, após o período de tempo especificado tiver decorrido desde a inicialização do dispositivo.
RTC - Queima a intenção pendente no momento especificado, mas não acorda o dispositivo.
RTC_WAKEUP - Acorda o dispositivo para disparar a intenção pendente no momento especificado.
exemplos ELAPSED_REALTIME_WAKEUP
Aqui estão alguns exemplos de como usar ELAPSED_REALTIME_WAKEUP .
Acorde o dispositivo para disparar o alarme em 30 minutos, e a cada 30 minutos depois disso:
// Hopefully your alarm will have a lower frequency than this!
alarmMgr.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
AlarmManager.INTERVAL_HALF_HOUR,
AlarmManager.INTERVAL_HALF_HOUR, alarmIntent);
Acorde o dispositivo para disparar um alarme de uma só vez (não-repetição) em um minuto:
private AlarmManager alarmMgr;
private PendingIntent alarmIntent;
...
alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, AlarmReceiver.class);
alarmIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
alarmMgr.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() +
60 * 1000, alarmIntent);
Exemplos RTC
Aqui estão alguns exemplos de como usar RTC_WAKEUP .
Acorde o dispositivo para disparar o alarme em aproximadamente 14:00, e repetir uma vez por dia, ao mesmo tempo:
// Set the alarm to start at approximately 2:00 pm
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 14);
// With setInexactRepeating(), you have to use one of the AlarmManager interval
// constants--in this case, AlarmManager.INTERVAL_DAY.
alarmMgr.setInexactRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
AlarmManager.INTERVAL_DAY, alarmIntent);
Acorde o dispositivo para disparar o alarme, precisamente 08:30, e a cada 20 minutos depois disso:
private AlarmManager alarmMgr;
private PendingIntent alarmIntent;
...
alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, AlarmReceiver.class);
alarmIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
// Set the alarm to start at 8:30 am
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 8);
calendar.set(Calendar.MINUTE, 30);
// setRepeating() lets you specify a precise custom interval--in this case,
// 20 minutes.
alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
1000 * 60 * 20, alarmIntent);
Decidir como o alarme precisa ser
Como descrito acima, a escolha do tipo de alarme é frequentemente o primeiro passo na criação de um alarme. Uma outra distinção é como você precisa que seu alarme seja. Para a maioria dos aplicativos, setInexactRepeating() é a escolha certa. Quando você usa esse método, o Android sincroniza vários alarmes inexata repetindo e dispara-los ao mesmo tempo. Isso reduz o consumo da bateria.
Para o app rara que tem horários rígidos, por exemplo, o alarme deve disparar precisamente às 8:30 am, e de hora em hora depois de usar setRepeating() . Mas você deve evitar o uso de alarmes exatos, se possível.
Com setInexactRepeating() , não é possível especificar um intervalo personalizado da maneira que você pode com setRepeating() . Tem de utilizar uma das constantes de intervalo, como INTERVAL_FIFTEEN_MINUTES , INTERVAL_DAY , e assim por diante. Veja AlarmManager para a lista completa.
Cancelar um alarme
Dependendo do seu aplicativo, você pode querer incluir a possibilidade de cancelar o alarme. Para cancelar um alarme, ligue para cancel() no Gerenciador de alarmes, passando o PendingIntent você não quer mais ao fogo. Por exemplo:
// Se o alarme foi definido, cancelá-lo.
if (alarmMgr! = null) {
alarmMgr.cancel (alarmIntent);
}
Iniciar um alarme quando o dispositivo é inicializado
Por padrão, todos os alarmes são cancelados quando um dispositivo é desligado. Para evitar que isso aconteça, você pode projetar seu aplicativo para reiniciar automaticamente um alarme de repetir se o usuário reinicia o dispositivo. Isso garante que o AlarmManager continuará fazendo a sua tarefa sem que o usuário precise reiniciar manualmente o alarme.