Programar alarmes

Os alarmes (com base na classe AlarmManager) oferecem uma maneira de realizar operações baseadas em tempo fora do ciclo de vida do aplicativo. Por exemplo, você pode usar um alarme para iniciar uma operação de longa duração, como iniciar um serviço uma vez por dia para fazer o download de uma previsão do tempo.

Os alarmes têm estas características:

  • Permitem que você dispare intents em horários e/ou intervalos definidos

  • É possível usá-los em conjunto com broadcast receivers para programar jobs ou WorkRequests para realizar outras operações.

  • Eles operam fora do aplicativo, então podem ser usados para acionar eventos ou ações mesmo quando o app não está em execução e até mesmo se o dispositivo estiver em modo de suspensão.

  • Eles ajudam a minimizar os requisitos de recursos do app. É possível programar operações sem depender de timers ou serviços em execução contínua.

Definir um alarme não exato

Quando um app define um alarme inexato, o sistema o aciona em algum momento no futuro. Os alarmes inexatos oferecem algumas garantias em relação ao momento de acionamento, respeitando as restrições de economia de bateria, como o modo Soneca.

Os desenvolvedores podem usar as seguintes garantias de API para personalizar o momento de envio de alarmes inexatos.

Acionar um alarme após um horário específico

Se o app chamar set(), setInexactRepeating() ou setAndAllowWhileIdle(), o alarme nunca vai tocar antes do horário de acionamento fornecido.

No Android 12 (nível 31 da API) e versões mais recentes, o sistema invoca o alarme em até uma hora após o horário de acionamento fornecido, a menos que haja restrições de economia de bateria em vigor, como a economia de bateria ou o modo de espera.

Acionar um alarme durante um período

Se o app chamar setWindow(), o alarme nunca vai tocar antes do horário de acionamento fornecido. A menos que haja restrições de economia de bateria em vigor, o alarme é acionado dentro da janela de tempo especificada, começando no horário de acionamento definido.

Se o app for direcionado ao Android 12 ou versões mais recentes, o sistema poderá atrasar a invocação de um alarme inexato com janela de tempo em pelo menos 10 minutos. Por esse motivo, os valores de parâmetro windowLengthMillis abaixo de 600000 geralmente são cortados para 600000. O sistema pode acomodar janelas menores, especialmente se o alarme estiver programado para ser acionado em um futuro próximo.

Acionar um alarme repetido em intervalos aproximadamente regulares

Se o app chamar setInexactRepeating(), o sistema vai invocar vários alarmes:

  1. O primeiro alarme é acionado dentro do período especificado, começando no horário de acionamento fornecido.
  2. Os alarmes seguintes geralmente são acionados após o término do período especificado. O tempo entre duas invocações consecutivas do alarme pode variar.

Definir um alarme exato

O sistema invoca um alarme exato em um momento preciso no futuro.

A maioria dos apps pode programar tarefas e eventos usando alarmes imprecisos para concluir vários casos de uso comuns. Se a funcionalidade principal do app depender de um alarme com tempo preciso, como um app de despertador ou de agenda, use um alarme exato.

Casos de uso que podem não exigir alarmes exatos

A lista a seguir mostra fluxos de trabalho comuns que podem não exigir um alarme exato:

Programação de operações de tempo durante o ciclo de vida do app
A classe Handler inclui vários métodos adequados para lidar com operações de tempo, como realizar um trabalho a cada n segundos, enquanto o app está ativo: postAtTime() e postDelayed(). Essas APIs dependem do tempo de atividade do sistema, e não do tempo real.
Trabalho programado em segundo plano, como atualizar o app e fazer upload de registros
O WorkManager oferece uma maneira de programar trabalhos periódicos com condição de tempo. É possível fornecer um intervalo de repetição e um flexInterval (mínimo de 15 minutos) para definir o ambiente de execução granular para o trabalho.
Ação especificada pelo usuário que acontece após um horário específico (mesmo que o sistema esteja inativo)
Use um alarme não exato. Chame setAndAllowWhileIdle() especificamente.
Ação especificada pelo usuário que acontece após um horário específico
Use um alarme não exato. Chame set() especificamente.
Ação especificada pelo usuário que pode acontecer em uma janela de tempo especificada
Use um alarme não exato. Chame setWindow() especificamente. Se o app for direcionado ao Android 12 ou versões mais recentes, a menor duração permitida da janela será de 10 minutos.

Maneiras de definir um alarme exato

O app pode definir alarmes exatos usando um dos métodos a seguir. Esses métodos são ordenados de modo que os que estão mais próximos da parte de baixo da lista atendam a tarefas mais críticas em termos de tempo, mas exijam mais recursos do sistema.

setExact()

Invocar um alarme em um horário quase preciso no futuro, desde que outras medidas de economia de bateria não estejam em vigor.

Use esse método para definir alarmes exatos, a menos que o trabalho do app seja urgente para o usuário.

setExactAndAllowWhileIdle()

Invoque um alarme em um horário quase preciso no futuro, mesmo que as medidas de economia de bateria estejam em vigor.

setAlarmClock()

Invocar um alarme em um horário preciso no futuro. Como esses alarmes são altamente visíveis para os usuários, o sistema nunca ajusta o horário de entrega deles. O sistema identifica esses alarmes como os mais críticos e sai dos modos de baixo consumo, se necessário, para acioná-los.

Consumo de recursos do sistema

Quando o sistema aciona alarmes exatos definidos pelo app, o dispositivo consome muitos recursos, como a bateria, principalmente se estiver no modo de economia de energia. Além disso, o sistema não pode agrupar facilmente essas solicitações para usar os recursos de maneira mais eficiente.

É altamente recomendável criar um alarme inexato sempre que possível. Para realizar um trabalho mais longo, programe-o usando WorkManager ou JobScheduler do BroadcastReceiver do alarme. Para realizar o trabalho enquanto o dispositivo está no modo Doze, crie um alarme não exato usando setAndAllowWhileIdle() e inicie um job com base no alarme.

Declarar a permissão de alarme exato adequada

Se o app for direcionado ao Android 12 ou versões mais recentes, será necessário receber o acesso especial "Alarmes e lembretes". Para fazer isso, declare a permissão SCHEDULE_EXACT_ALARM no arquivo de manifesto do app, conforme mostrado no snippet de código abaixo:

<manifest ...>
    <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/>
    <application ...>
        ...
    </application>
</manifest>

Se o app for destinado ao Android 13 (nível 33 da API) ou versões mais recentes, você poderá declarar a permissão SCHEDULE_EXACT_ALARM ou USE_EXACT_ALARM.

<manifest ...>
    <uses-permission android:name="android.permission.USE_EXACT_ALARM"/>
    <application ...>
        ...
    </application>
</manifest>

Embora as permissões SCHEDULE_EXACT_ALARM e USE_EXACT_ALARM sinalizem os mesmos recursos, elas são concedidas de forma diferente e oferecem suporte a casos de uso distintos. O app só deve usar alarmes exatos e declarar a permissão SCHEDULE_EXACT_ALARM ou USE_EXACT_ALARM se uma função voltada ao usuário exigir ações com tempo preciso.

USE_EXACT_ALARM

SCHEDULE_EXACT_ALARM

  • Concedida pelo usuário
  • Conjunto mais amplo de casos de uso
  • Os apps precisam confirmar que a permissão não foi revogada

A permissão SCHEDULE_EXACT_ALARM não é concedida previamente a novas instalações de apps destinados ao Android 13 (nível 33 da API) e versões mais recentes. Se um usuário transferir dados do app para um dispositivo com o Android 14 usando uma operação de backup e restauração, a permissão SCHEDULE_EXACT_ALARM será negada no novo dispositivo. No entanto, se um app já tiver essa permissão, ela será concedida previamente quando o dispositivo for atualizado para o Android 14.

Observação: se o alarme exato for definido usando um objeto OnAlarmListener, como na API setExact, a permissão SCHEDULE_EXACT_ALARM não será necessária.

Como usar a permissão SCHEDULE_EXACT_ALARM

Ao contrário de USE_EXACT_ALARM, a permissão SCHEDULE_EXACT_ALARM precisa ser concedida pelo usuário. Tanto o usuário quanto o sistema podem revogar a permissão SCHEDULE_EXACT_ALARM.

Para verificar se a permissão foi concedida ao app, chame canScheduleExactAlarms() antes de tentar definir um alarme exato. Quando a permissão SCHEDULE_EXACT_ALARM é revogada, o app é interrompido, e todos os alarmes exatos futuros são cancelados. Isso também significa que o valor retornado por canScheduleExactAlarms() permanece válido durante todo o ciclo de vida do app.

Quando a permissão SCHEDULE_EXACT_ALARMS é concedida ao app, o sistema envia a transmissão ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED. O app precisa implementar um broadcast receiver que faça o seguinte:

  1. Confirma se o app ainda tem o acesso especial. Para fazer isso, chame o método canScheduleExactAlarms(). Essa verificação protege o app no caso de o usuário conceder a permissão e revogá-la quase imediatamente depois.
  2. reprograma todos os alarmes exatos de que o app precisa, com base no estado atual dele; Essa lógica precisa ser parecida com a de quando o app recebe a transmissão ACTION_BOOT_COMPLETED.

Pedir que os usuários concedam a permissão SCHEDULE_EXACT_ALARM

A opção &quot;Autorizar a definição de alarmes e lembretes&quot;
Figura 1. Página de acesso especial aos "Alarmes e lembretes" nas configurações do sistema, onde os usuários podem autorizar o app a definir alarmes exatos.

Se necessário, você pode enviar os usuários para a tela Alarmes e lembretes nas configurações do sistema, como mostrado na Figura 1. Para isso, siga estas etapas:

  1. Na IU do app, explique ao usuário por que o app precisa programar alarmes exatos.
  2. Invoque uma intent que inclua a ação da intent ACTION_REQUEST_SCHEDULE_EXACT_ALARM.

Definir um alarme recorrente

Os alarmes repetidos permitem que o sistema notifique o app de forma recorrente.

Um alarme mal projetado pode causar o consumo da bateria e colocar uma carga significativa nos servidores. Por esse motivo, no Android 4.4 (nível 19 da API) e versões mais recentes, todos os alarmes repetidos são alarmes inexatos.

Um alarme recorrente tem as seguintes características:

  • Um tipo de alarme. Para saber mais, consulte Escolher um tipo de alarme.

  • Um tempo de acionamento. Se o horário de acionamento especificado estiver no passado, o alarme será acionado imediatamente.

  • O intervalo do alarme. Por exemplo, uma vez por dia, a cada hora ou a cada 5 minutos.

  • Um intent pendente que é acionado quando o alarme é disparado. Quando você define um segundo alarme que usa a mesma intent pendente, ele substitui o alarme original.

Para cancelar uma PendingIntent(), transmita FLAG_NO_CREATE para PendingIntent.getService() para receber uma instância da intent (se houver) e transmita essa intent para AlarmManager.cancel().

Kotlin

val alarmManager =
    context.getSystemService(Context.ALARM_SERVICE) as? AlarmManager
val pendingIntent =
    PendingIntent.getService(context, requestId, intent,
                                PendingIntent.FLAG_NO_CREATE)
if (pendingIntent != null && alarmManager != null) {
  alarmManager.cancel(pendingIntent)
}

Java

AlarmManager alarmManager =
    (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
PendingIntent pendingIntent =
    PendingIntent.getService(context, requestId, intent,
                                PendingIntent.FLAG_NO_CREATE);
if (pendingIntent != null && alarmManager != null) {
  alarmManager.cancel(pendingIntent);
}

Escolher um tipo de alarme

Uma das primeiras considerações ao usar um alarme recorrente é o tipo dele.

Há dois tipos gerais de relógio para alarmes: "tempo real decorrido" e "relógio em tempo real" (RTC, na sigla em inglês). O tempo real decorrido usa o "tempo desde a inicialização do sistema" como referência, e o relógio em tempo real usa o horário UTC (relógio de parede). Isso significa que o tempo real decorrido é adequado para definir um alarme com base na passagem do tempo (por exemplo, um alarme que é acionado a cada 30 segundos), já que não é afetado pelo fuso horário ou pela localidade. O tipo de relógio em tempo real é mais adequado para alarmes que dependem da localidade atual.

Ambos os tipos têm uma versão de "ativação", que ativa a CPU do dispositivo se a tela estiver desligada. Isso garante que o alarme seja acionado no horário programado. Isso é útil se o app tiver uma dependência de tempo. Por exemplo, se ele tiver uma janela limitada para realizar uma operação específica. Se você não usar a versão de ativação do tipo de alarme, todos os alarmes repetidos serão acionados quando o dispositivo for ativado novamente.

Se você só precisa que o alarme seja acionado em um intervalo específico (por exemplo, a cada meia hora), use um dos tipos de tempo real decorrido. Em geral, essa é a melhor opção.

Se você precisar que o alarme seja acionado em um horário específico do dia, escolha um dos tipos de relógio em tempo real baseados em relógio. No entanto, essa abordagem pode ter algumas desvantagens. O app pode não ser traduzido corretamente para outras localidades e, se o usuário mudar a configuração de horário do dispositivo, isso poderá causar um comportamento inesperado no app. O uso de um tipo de alarme de relógio em tempo real também não é escalonável, conforme discutido acima. Recomendamos que você use um alarme de "tempo real decorrido" se puder.

Veja a lista de tipos:

  • ELAPSED_REALTIME: dispara a intent pendente com base no tempo decorrido desde que o dispositivo foi inicializado, mas não ativa o dispositivo. O tempo decorrido inclui qualquer período em que o dispositivo estava em repouso.

  • ELAPSED_REALTIME_WAKEUP: ativa o dispositivo e aciona a intent pendente após o período especificado desde a inicialização do dispositivo.

  • RTC: dispara a intent pendente no horário especificado, mas não ativa o dispositivo.

  • RTC_WAKEUP: ativa o dispositivo para disparar a intent pendente no horário especificado.

Exemplos de alarmes de "tempo real decorrido"

Veja alguns exemplos de como usar o ELAPSED_REALTIME_WAKEUP

Ative o dispositivo para disparar o alarme em 30 minutos e a cada 30 minutos depois disso:

Kotlin

// Hopefully your alarm will have a lower frequency than this!
alarmMgr?.setInexactRepeating(
        AlarmManager.ELAPSED_REALTIME_WAKEUP,
        SystemClock.elapsedRealtime() + AlarmManager.INTERVAL_HALF_HOUR,
        AlarmManager.INTERVAL_HALF_HOUR,
        alarmIntent
)

Java

// Hopefully your alarm will have a lower frequency than this!
alarmMgr.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
        SystemClock.elapsedRealtime() + AlarmManager.INTERVAL_HALF_HOUR,
        AlarmManager.INTERVAL_HALF_HOUR, alarmIntent);

Ativar o dispositivo para disparar um alarme único (não recorrente) em um minuto:

Kotlin

private var alarmMgr: AlarmManager? = null
private lateinit var alarmIntent: PendingIntent
...
alarmMgr = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
alarmIntent = Intent(context, AlarmReceiver::class.java).let { intent ->
    PendingIntent.getBroadcast(context, 0, intent, 0)
}

alarmMgr?.set(
        AlarmManager.ELAPSED_REALTIME_WAKEUP,
        SystemClock.elapsedRealtime() + 60 * 1000,
        alarmIntent
)

Java

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 de alarmes de "relógio em tempo real"

Veja alguns exemplos de como usar RTC_WAKEUP.

Ative o dispositivo para disparar o alarme aproximadamente às 14h e repetir uma vez por dia no mesmo horário:

Kotlin

// Set the alarm to start at approximately 2:00 p.m.
val calendar: Calendar = Calendar.getInstance().apply {
    timeInMillis = System.currentTimeMillis()
    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.timeInMillis,
        AlarmManager.INTERVAL_DAY,
        alarmIntent
)

Java

// Set the alarm to start at approximately 2:00 p.m.
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);

Ative o dispositivo para disparar o alarme exatamente às 8h30 e a cada 20 minutos depois disso:

Kotlin

private var alarmMgr: AlarmManager? = null
private lateinit var alarmIntent: PendingIntent
...
alarmMgr = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
alarmIntent = Intent(context, AlarmReceiver::class.java).let { intent ->
    PendingIntent.getBroadcast(context, 0, intent, 0)
}

// Set the alarm to start at 8:30 a.m.
val calendar: Calendar = Calendar.getInstance().apply {
    timeInMillis = System.currentTimeMillis()
    set(Calendar.HOUR_OF_DAY, 8)
    set(Calendar.MINUTE, 30)
}

// setRepeating() lets you specify a precise custom interval--in this case,
// 20 minutes.
alarmMgr?.setRepeating(
        AlarmManager.RTC_WAKEUP,
        calendar.timeInMillis,
        1000 * 60 * 20,
        alarmIntent
)

Java

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 a.m.
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 a precisão que o alarme precisa ter

Como descrito anteriormente, escolher o tipo de alarme geralmente é a primeira etapa para criar um alarme. Outra distinção é o nível de precisão necessário para o alarme. Para a maioria dos apps, setInexactRepeating() é a escolha certa. Quando você usa esse método, o Android sincroniza vários alarmes inexatos e os aciona ao mesmo tempo. Isso reduz o consumo da bateria.

Evite usar alarmes exatos, se possível. No entanto, para os raros apps que têm requisitos de tempo rígidos, é possível definir um alarme exato chamando setRepeating().

Com setInexactRepeating(), não é possível especificar um intervalo personalizado como é possível com setRepeating(). É preciso usar uma das constantes de intervalo, como INTERVAL_FIFTEEN_MINUTES, INTERVAL_DAY e assim por diante. Consulte AlarmManager para ver a lista completa.

Cancelar um alarme

Dependendo do app, convém incluir a capacidade de cancelar o alarme. Para cancelar um alarme, chame cancel() no Gerenciador de Alarmes, transmitindo a PendingIntent que você não quer mais disparar. Exemplo:

Kotlin

// If the alarm has been set, cancel it.
alarmMgr?.cancel(alarmIntent)

Java

// If the alarm has been set, cancel it.
if (alarmMgr!= null) {
    alarmMgr.cancel(alarmIntent);
}

Iniciar um alarme quando o dispositivo é reiniciado

Por padrão, todos os alarmes são cancelados quando um dispositivo é desligado. Para evitar que isso aconteça, você pode projetar o aplicativo para reiniciar automaticamente um alarme recorrente se o usuário reiniciar o dispositivo. Isso garante que o AlarmManager continue realizando a tarefa sem que o usuário precise reiniciar o alarme manualmente.

Veja as etapas:

  1. Defina a permissão RECEIVE_BOOT_COMPLETED no manifesto do aplicativo. Isso permite que o app receba o ACTION_BOOT_COMPLETED que é transmitido depois que o sistema conclui a inicialização. Isso só funciona se o app já tiver sido iniciado pelo usuário pelo menos uma vez:

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
  2. Implemente um BroadcastReceiver para receber a transmissão:

    Kotlin

    class SampleBootReceiver : BroadcastReceiver() {
    
        override fun onReceive(context: Context, intent: Intent) {
            if (intent.action == "android.intent.action.BOOT_COMPLETED") {
                // Set the alarm here.
            }
        }
    }

    Java

    public class SampleBootReceiver extends BroadcastReceiver {
    
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) {
                // Set the alarm here.
            }
        }
    }
  3. Adicione o receptor ao arquivo de manifesto do app com um filtro de intent que filtra a ação ACTION_BOOT_COMPLETED:

    <receiver android:name=".SampleBootReceiver"
            android:enabled="false">
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED"></action>
        </intent-filter>
    </receiver>

    No manifesto, o receptor de inicialização está definido como android:enabled="false". Isso significa que o receptor não será chamado, a menos que o aplicativo o ative explicitamente. Isso impede que o receptor de inicialização seja chamado desnecessariamente. É possível ativar um receptor (por exemplo, se o usuário definir um alarme) da seguinte forma:

    Kotlin

    val receiver = ComponentName(context, SampleBootReceiver::class.java)
    
    context.packageManager.setComponentEnabledSetting(
            receiver,
            PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
            PackageManager.DONT_KILL_APP
    )

    Java

    ComponentName receiver = new ComponentName(context, SampleBootReceiver.class);
    PackageManager pm = context.getPackageManager();
    
    pm.setComponentEnabledSetting(receiver,
            PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
            PackageManager.DONT_KILL_APP);

    Depois de ativar o receptor dessa forma, ele vai permanecer ativado, mesmo que o usuário reinicie o dispositivo. Em outras palavras, a ativação programática do receptor substitui a configuração do manifesto, mesmo em reinicializações. O receptor vai permanecer ativado até que o app o desative. É possível desativar um receptor (por exemplo, se o usuário cancelar um alarme) da seguinte maneira:

    Kotlin

    val receiver = ComponentName(context, SampleBootReceiver::class.java)
    
    context.packageManager.setComponentEnabledSetting(
            receiver,
            PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
            PackageManager.DONT_KILL_APP
    )

    Java

    ComponentName receiver = new ComponentName(context, SampleBootReceiver.class);
    PackageManager pm = context.getPackageManager();
    
    pm.setComponentEnabledSetting(receiver,
            PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
            PackageManager.DONT_KILL_APP);

Invocar alarmes enquanto o dispositivo está no modo Soneca

Os dispositivos com o Android 6.0 (nível 23 da API) oferecem suporte ao modo Soneca, que ajuda a prolongar a duração da bateria. Os alarmes não são acionados quando o dispositivo está no modo Soneca. Todos os alarmes programados são adiados até que o dispositivo saia desse modo. Se você precisar concluir o trabalho mesmo quando o dispositivo estiver inativo, há várias opções disponíveis:

  • Defina um alarme exato.

  • Use a API WorkManager, que foi criada para realizar trabalhos em segundo plano. É possível indicar que o sistema precisa acelerar o trabalho para que ele seja concluído o mais rápido possível. Para mais informações, consulte Agendar tarefas com o WorkManager.

Práticas recomendadas

Cada escolha que você faz ao projetar o alarme recorrente pode ter consequências na forma como o app usa (ou abusa) dos recursos do sistema. Por exemplo, imagine um app muito usado que sincroniza com um servidor. Se a operação de sincronização for baseada no horário e todas as instâncias do app forem sincronizadas às 23h, a carga no servidor poderá resultar em alta latência ou até mesmo "negação de serviço". Siga estas práticas recomendadas para o uso de alarmes:

  • Adicione aleatoriedade (jitter) a todas as solicitações de rede que são acionadas como resultado de um alarme repetido:

    • Faça qualquer trabalho local quando o alarme for acionado. "Trabalho local" significa qualquer coisa que não atinja um servidor ou exija os dados dele.

    • Ao mesmo tempo, programe o alarme que contém as solicitações de rede para ser acionado em um período aleatório.

  • Mantenha a frequência do alarme em um nível mínimo.

  • Não ativar o dispositivo desnecessariamente (esse comportamento é determinado pelo tipo de alarme, conforme descrito em Escolher um tipo de alarme).

  • Não faça com que o horário de acionamento do alarme seja mais preciso do que o necessário.

    Use setInexactRepeating() em vez de setRepeating(). Quando você usa setInexactRepeating(), o Android sincroniza alarmes repetidos de vários apps e os aciona ao mesmo tempo. Isso reduz o número total de vezes que o sistema precisa ativar o dispositivo, reduzindo o consumo da bateria. A partir do Android 4.4 (nível 19 da API), todos os alarmes recorrentes são alarmes inexatos. Embora setInexactRepeating() seja uma melhoria em relação a setRepeating(), ele ainda pode sobrecarregar um servidor se todas as instâncias de um app acessarem o servidor ao mesmo tempo. Portanto, para solicitações de rede, adicione alguma aleatoriedade aos alarmes, conforme discutido anteriormente.

  • Evite basear seu alarme na hora do relógio, se possível.

    Alarmes recorrentes baseados em um gatilho preciso não funcionam bem. Use ELAPSED_REALTIME se possível. Os diferentes tipos de alarme são descritos em mais detalhes na seção a seguir.