Cómo programar alarmas

Las alarmas (basadas en la clase AlarmManager) te brindan una manera de realizar operaciones basadas en el tiempo fuera del ciclo de vida de tu aplicación. Por ejemplo, puedes usar una alarma para iniciar una operación prolongada, como iniciar un servicio una vez al día para descargar el pronóstico del tiempo.

Las alarmas tienen las siguientes características:

  • Te permiten activar intents en horas o intervalos determinados.

  • Puedes usarlos junto con receptores de emisión para programar trabajos o, también, WorkRequests para realizar otras operaciones.

  • Funcionan fuera de tu aplicación, por lo que puedes usarlas para activar eventos o acciones incluso cuando la app no está en ejecución y el dispositivo en sí está suspendido.

  • Ayudan a minimizar los requisitos de recursos de tu app. Puedes programar operaciones sin depender de cronómetros o de servicios que se ejecuten continuamente.

Establece una alarma inexacta

Cuando una app establece una alarma inexacta, el sistema la entrega en algún momento en el futuro. Las alarmas inexactas proporcionan algunas garantías sobre la sincronización de la emisión de la alarma y respetan las restricciones de ahorro de batería, como la función Descanso.

Los desarrolladores pueden aprovechar las siguientes garantías de API para personalizar el momento de la entrega inexacta de alarmas.

Cómo activar una alarma después de una hora específica

Si tu app llama a set(), setInexactRepeating() o setAndAllowWhileIdle(), la alarma nunca suena antes de la hora de activación proporcionada.

En Android 12 (nivel de API 31) y versiones posteriores, el sistema invoca la alarma en un plazo de una hora a partir del tiempo de activación proporcionado, a menos que estén vigentes restricciones de ahorro de batería, como el ahorro de batería o Descanso.

Cómo activar una alarma durante un período determinado

Si tu app llama a setWindow(), la alarma nunca suena antes del tiempo de activación proporcionado. A menos que estén vigentes alguna restricción de ahorro de batería, la alarma se envía dentro del período especificado a partir del tiempo de activación determinado.

Si tu app se orienta a Android 12 o versiones posteriores, el sistema puede retrasar la invocación de una alarma inexacta con ventana de tiempo al menos 10 minutos. Por este motivo, los valores del parámetro windowLengthMillis en 600000 se recortan a 600000.

Reproducir una alarma que se repita en intervalos prácticamente regulares

Si tu app llama a setInexactRepeating(), el sistema invoca varias alarmas:

  1. La primera alarma suena dentro del período especificado, a partir del momento de activación determinado.
  2. Por lo general, las alarmas posteriores se activan después de que transcurre el período especificado. El tiempo entre dos invocaciones consecutivas de la alarma puede variar.

Establecer una alarma exacta

El sistema invoca una alarma exacta en un momento preciso en el futuro.

La mayoría de las apps pueden programar tareas y eventos con alarmas inexactas para completar varios casos de uso comunes. Si la funcionalidad principal de tu app depende de una alarma con una hora precisa, por ejemplo, una app de alarma o de calendario, está bien usar una alarma exacta.

Casos de uso que podrían no exigir alarmas exactas

En la siguiente lista, se muestran los flujos de trabajo comunes que pueden no requerir una alarma exacta:

Programa operaciones de tiempo durante el ciclo de vida de tu app
La clase Handler incluye varios métodos útiles para controlar las operaciones de sincronización, como realizar trabajos cada n segundos, mientras tu app está activa: postAtTime() y postDelayed(). Ten en cuenta que estas APIs se basan en el tiempo de actividad del sistema y no en el tiempo real.
Tarea en segundo plano programada, por ejemplo, actualizar la app y subir registros
WorkManager proporciona una forma de programar trabajos periódicos sensibles al tiempo. Puedes proporcionar un intervalo de repetición y flexInterval (15 minutos como mínimo) para definir el tiempo de ejecución detallado de la tarea.
Acción especificada por el usuario que debe ocurrir después de un tiempo específico (incluso si el sistema está inactivo)
Usa una alarma inexacta. Específicamente, llama a setAndAllowWhileIdle().
Acción especificada por el usuario que debe ocurrir después de un tiempo específico
Usa una alarma inexacta. Específicamente, llama a set().
Acción especificada por el usuario que puede ocurrir dentro de un período específico
Usa una alarma inexacta. Específicamente, llama a setWindow(). Ten en cuenta que, si tu app se orienta a Android 12 o versiones posteriores, la duración mínima permitida es de 10 minutos.

Formas de establecer una alarma exacta

Tu app puede establecer alarmas exactas mediante uno de los siguientes métodos. Estos métodos se ordenan de modo que los que estén más cerca de la parte inferior de la lista entreguen más tareas urgentes, pero exigen más recursos del sistema.

setExact()

Invoca una alarma en un momento casi preciso en el futuro, siempre que no estén vigentes otras medidas de ahorro de batería.

Usa este método para establecer alarmas exactas, a menos que el trabajo de tu app sea urgente para el usuario.

setExactAndAllowWhileIdle()

Invoca una alarma en un momento casi preciso en el futuro, incluso si hay medidas de ahorro de batería vigentes.

setAlarmClock()

Invoca una alarma en un momento preciso en el futuro. Como estas alarmas son muy visibles para los usuarios, el sistema nunca ajusta su hora de entrega. El sistema identifica estas alarmas como las más críticas y deja modos de bajo consumo si es necesario para activar las alarmas.

Consumo de recursos del sistema

Cuando el sistema activa alarmas exactas que establece tu app, el dispositivo consume una gran cantidad de recursos, como la duración de batería, especialmente si está en modo de ahorro de energía. Además, el sistema no puede agrupar estas solicitudes fácilmente para usar los recursos de manera más eficiente.

Te recomendamos que crees una alarma inexacta siempre que sea posible. Para realizar un trabajo más largo, prográmalo con WorkManager o JobScheduler del BroadcastReceiver de la alarma. Para realizar tareas mientras el dispositivo está en modo Descanso, crea una alarma inexacta con setAndAllowWhileIdle() y comienza una tarea desde la alarma.

Declara el permiso exacto de la alarma correspondiente

Si la app se orienta a Android 12 o versiones posteriores, debes obtener el acceso especial de apps a "Alarmas y recordatorios". Para hacerlo, declara el permiso SCHEDULE_EXACT_ALARM en el archivo de manifiesto de la app, como se muestra en el siguiente fragmento de código:

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

Si tu app se orienta a Android 13 (nivel de API 33) o versiones posteriores, tienes la opción de declarar el permiso SCHEDULE_EXACT_ALARM o USE_EXACT_ALARM.

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

Si bien los permisos SCHEDULE_EXACT_ALARM y USE_EXACT_ALARM indican las mismas capacidades, se otorgan de manera diferente y admiten distintos casos de uso. Tu app debe usar alarmas exactas y declarar el permiso SCHEDULE_EXACT_ALARM o USE_EXACT_ALARM solo si una función para el usuario requiere acciones con tiempos precisos.

USE_EXACT_ALARM

SCHEDULE_EXACT_ALARM

  • Otorgado por el usuario
  • Conjunto más amplio de casos de uso
  • Las apps deben confirmar que no se revocó el permiso

Usa el permiso SCHEDULE_EXACT_ALARM

A diferencia de USE_EXACT_ALARM, el usuario debe otorgar el permiso SCHEDULE_EXACT_ALARM. Tanto el usuario como el sistema pueden revocar el permiso SCHEDULE_EXACT_ALARM.

Para verificar si se otorgó el permiso a tu app, llama a canScheduleExactAlarms() antes de intentar establecer una alarma exacta. Cuando se revoca el permiso SCHEDULE_EXACT_ALARM para tu app, esta se detiene y se cancelan todas las alarmas exactas futuras. Esto también significa que el valor que muestra canScheduleExactAlarms() sigue siendo válido durante todo el ciclo de vida de la app.

Cuando se otorga el permiso SCHEDULE_EXACT_ALARMS a tu app, el sistema le envía la transmisión ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED. Tu app debe implementar un receptor de emisión que haga lo siguiente:

  1. Confirma que tu app aún tiene el acceso especial de apps. Para ello, llama a canScheduleExactAlarms(). Esta verificación protege a tu app del caso en el que el usuario le otorga el permiso y, luego, la revoca casi de inmediato.
  2. Reprograma cualquier alarma exacta que necesite la app, según su estado actual. Esta lógica debería ser similar a lo que hace la app cuando recibe la emisión ACTION_BOOT_COMPLETED.

Solicita a los usuarios que otorguen el permiso SCHEDULE_EXACT_ALARM

La opción se denomina &quot;Permitir configuración de alarmas y recordatorios&quot;
Figura 1: Página de acceso especial a "Alarmas y recordatorios" en la configuración del sistema, en la que los usuarios pueden permitir que la app establezca alarmas exactas.

Si es necesario, puedes enviar a los usuarios a la pantalla Alarmas y recordatorios en la configuración del sistema, como se muestra en la Figura 1. Para ello, completa los siguientes pasos:

  1. En la IU de la app, explícale al usuario por qué la app debe programar alarmas exactas.
  2. Invoca un intent que incluya la acción de intent ACTION_REQUEST_SCHEDULE_EXACT_ALARM.

Cómo establecer una alarma repetitiva

Las alarmas recurrentes permiten que el sistema le notifique a tu app sobre un programa recurrente.

Una alarma mal diseñada puede agotar la batería y sobrecargar los servidores. Por este motivo, en Android 4.4 (nivel de API 19) y versiones posteriores, todas las alarmas repetitivas son alarmas inexactas.

Una alarma repetitiva tiene las siguientes características:

  • Un tipo de alarma (Para obtener más información, consulta Cómo elegir un tipo de alarma)

  • Una hora de activación Si la hora de activación que especificas es en el pasado, la alarma se activará de inmediato.

  • El intervalo de la alarma Por ejemplo, una vez al día, cada hora o cada 5 minutos.

  • Un intent pendiente que se activa cuando se activa la alarma Cuando configuras una segunda alarma que usa el mismo intent pendiente, esta reemplaza la alarma original.

Para cancelar un PendingIntent(), pasa FLAG_NO_CREATE a PendingIntent.getService() para obtener una instancia del intent (si existe) y, luego, pasa ese intent a 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);
}

Cómo elegir un tipo de alarma

Una de las primeras consideraciones al usar una alarma repetitiva es cuál debería ser su tipo.

Hay dos tipos de reloj generales para las alarmas: "tiempo real transcurrido" y "reloj en tiempo real" (RTC). En tiempo real transcurrido, se usa el “tiempo desde el inicio del sistema” como referencia, y el reloj en tiempo real usa la hora UTC (reloj de pared). Esto significa que el tiempo real transcurrido es adecuado para establecer una alarma basada en el paso del tiempo (por ejemplo, una alarma que se activa cada 30 segundos), ya que no se ve afectada por la zona horaria ni la configuración regional. El tipo de reloj en tiempo real es más adecuado para las alarmas que dependen de la configuración regional actual.

Ambos tipos tienen una versión de "activación", que indica que se active la CPU del dispositivo si la pantalla está apagada. De esta manera, se garantiza que la alarma se active a la hora programada. Esto es útil si tu app tiene una dependencia de tiempo. Por ejemplo, si tiene un período limitado para realizar una operación en particular. Si no usas la versión de activación de tu tipo de alarma, todas las alarmas repetitivas se activarán cuando se active el dispositivo.

Si solo necesitas que la alarma se active en un intervalo determinado (por ejemplo, cada media hora), usa uno de los tipos de tiempo real transcurrido. En general, esta es la mejor opción.

Si necesitas que la alarma se active a una hora determinada del día, elige uno de los tipos de reloj en tiempo real. Sin embargo, ten en cuenta que este enfoque puede tener algunas desventajas. Es posible que la app no se traduzca correctamente a otras configuraciones regionales y, si el usuario cambia la configuración de hora del dispositivo, podría provocar un comportamiento inesperado en tu app. El uso de un tipo de alarma de reloj en tiempo real tampoco se ajusta bien, como se explicó anteriormente. Te recomendamos que uses una alarma de "tiempo real transcurrido" si es posible.

A continuación, se muestra una lista de los tipos:

  • ELAPSED_REALTIME: Activa el intent pendiente en función de la cantidad de tiempo transcurrido desde que se inició el dispositivo, pero no lo activa. El tiempo transcurrido incluye cualquier tiempo durante el cual el dispositivo estuvo suspendido.

  • ELAPSED_REALTIME_WAKEUP: Activa el dispositivo y activa el intent pendiente una vez transcurrido el tiempo especificado desde el inicio del dispositivo.

  • RTC: Activa el intent pendiente a la hora especificada, pero no activa el dispositivo.

  • RTC_WAKEUP: Activa el dispositivo para activar el intent pendiente a la hora especificada.

Ejemplos de alarmas de tiempo real transcurrido

Estos son algunos ejemplos del uso de ELAPSED_REALTIME_WAKEUP

Activa el dispositivo para activar la alarma en 30 minutos, y cada 30 minutos después de eso:

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);

Activa el dispositivo para activar una única alarma (no repetitiva) en un 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);

Ejemplos de alarmas de reloj en tiempo real

Estos son algunos ejemplos del uso de RTC_WAKEUP.

Activa el dispositivo para activar la alarma aproximadamente a las 2:00 p.m. y repite una vez al día a la misma hora:

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);

Activa el dispositivo para activar la alarma precisamente a las 8:30 a.m. y, luego, cada 20 minutos:

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);

Cómo decidir qué tan precisa debe ser la alarma

Como se describió anteriormente, elegir el tipo de alarma suele ser el primer paso para crear una. Otra distinción es qué tan precisa necesitas que sea la alarma. Para la mayoría de las apps, setInexactRepeating() es la opción correcta. Cuando usas este método, Android sincroniza varias alarmas repetitivas que no son exactas y las activa al mismo tiempo. De esta manera, se reduce el consumo de batería.

Si es posible, evita usar alarmas exactas. Sin embargo, en el caso de apps poco comunes que tienen requisitos de tiempo rígidos, puedes establecer una alarma exacta llamando a setRepeating().

Con setInexactRepeating(), no puedes especificar un intervalo personalizado como lo haces con setRepeating(). Debes usar una de las constantes de intervalo, como INTERVAL_FIFTEEN_MINUTES, INTERVAL_DAY, etcétera. Consulta AlarmManager para ver la lista completa.

Cancela una alarma

Según tu app, es posible que quieras incluir la capacidad para cancelar la alarma. Para cancelar una alarma, llama a cancel() en Alarm Manager y pasa el PendingIntent que ya no quieras activar. Por ejemplo:

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);
}

Cómo iniciar una alarma cuando se reinicia el dispositivo

De manera predeterminada, todas las alarmas se cancelan cuando se apaga un dispositivo. Para evitar que esto suceda, puedes diseñar tu aplicación de modo que reinicie automáticamente una alarma recurrente si el usuario reinicia el dispositivo. De esta manera, se garantiza que el AlarmManager continúe realizando la tarea sin que el usuario tenga que reiniciar la alarma manualmente.

A continuación, se indican los pasos que debes seguir:

  1. Configura el permiso RECEIVE_BOOT_COMPLETED en el manifiesto de tu aplicación. De esta manera, tu app puede recibir el ACTION_BOOT_COMPLETED que se transmite una vez que el sistema termina de iniciarse (esto solo funciona si el usuario ya inició la app al menos una vez):

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
  2. Implementa un BroadcastReceiver para recibir la transmisión:

    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. Agrega el receptor al archivo de manifiesto de tu app con un filtro de intents que filtre la acción ACTION_BOOT_COMPLETED:

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

    Ten en cuenta que, en el manifiesto, el receptor de inicio está configurado en android:enabled="false". Esto significa que no se llamará al receptor, a menos que la aplicación lo habilite explícitamente. De esta manera, se evita que se llame al receptor de arranque innecesariamente. Puedes habilitar un receptor (por ejemplo, si el usuario establece una alarma) de la siguiente manera:

    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);
    

    Una vez que habilites el receptor de esta manera, permanecerá habilitado, incluso si el usuario reinicia el dispositivo. En otras palabras, si se habilita el receptor de manera programática, se anula la configuración del manifiesto, incluso después de los reinicios. El receptor permanecerá habilitado hasta que tu app lo inhabilite. Puedes inhabilitar un receptor (por ejemplo, si el usuario cancela una alarma) de la siguiente manera:

    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);
    

Invoca alarmas mientras el dispositivo está en modo Descanso

Los dispositivos que ejecutan Android 6.0 (nivel de API 23) admiten el modo Descanso, que ayuda a extender la duración de batería del dispositivo. Las alarmas no se activan cuando el dispositivo está en modo Descanso. Todas las alarmas programadas se aplazan hasta que el dispositivo salga del modo Descanso. Si necesitas completar un trabajo incluso cuando el dispositivo está inactivo, hay varias opciones disponibles:

  • Establece una alarma exacta.

  • Usa la API de WorkManager, que está diseñada para realizar trabajos en segundo plano. Puedes indicar que el sistema debe acelerar tu trabajo para que finalice lo antes posible. Para obtener más información, consulta Cómo programar tareas con WorkManager.

Prácticas recomendadas

Cada decisión que tomes al diseñar tu alarma recurrente puede tener consecuencias en la forma en que tu app usa (o abusa) de los recursos del sistema. Por ejemplo, imagina una app popular que se sincroniza con un servidor. Si la operación de sincronización se basa en la hora del reloj y cada instancia de la app se sincroniza a las 11:00 p.m., la carga en el servidor podría generar una latencia alta o incluso “denegación del servicio”. Sigue estas prácticas recomendadas para usar las alarmas:

  • Agrega aleatorización (jitter) a cualquier solicitud de red que se active como resultado de una alarma repetitiva:

    • Realiza las tareas locales cuando se active la alarma. "Trabajo local" se refiere a cualquier cosa que no llegue a un servidor o que requiera datos de este.

    • Al mismo tiempo, programa la alarma que contenga las solicitudes de red para que se active en algún período aleatorio.

  • Mantén la frecuencia de la alarma al mínimo.

  • No actives el dispositivo innecesariamente (este comportamiento se determina por el tipo de alarma, como se describe en Cómo elegir un tipo de alarma).

  • No hagas que el tiempo de activación de la alarma sea más preciso de lo necesario.

    Usa setInexactRepeating() en lugar de setRepeating(). Cuando usas setInexactRepeating(), Android sincroniza las alarmas repetitivas de varias apps y las activa al mismo tiempo. De esta manera, se reduce la cantidad total de veces que el sistema debe activar el dispositivo, lo que reduce el consumo de la batería. A partir de Android 4.4 (nivel de API 19), todas las alarmas repetitivas son alarma inexacta. Ten en cuenta que, si bien setInexactRepeating() es una mejora en comparación con setRepeating(), puede abrumar al servidor si cada instancia de una app llega a él casi al mismo tiempo. Por lo tanto, en el caso de las solicitudes de red, agrega un poco de aleatorización a las alarmas, como se explicó anteriormente.

  • Si es posible, evita basar tu alarma en la hora del reloj.

    Las alarmas repetitivas que se basan en una hora de activación precisa no se escalan bien. Usa ELAPSED_REALTIME si puedes. Los diferentes tipos de alarmas se describen con más detalle en la siguiente sección.