¿Cómo verificar si AlarmManager ya tiene una alarma configurada?


231

Cuando mi aplicación se inicia, quiero que verifique si una alarma particular (registrada a través de AlarmManager) ya está configurada y ejecutándose. Los resultados de google parecen indicar que no hay forma de hacer esto. ¿Esto sigue siendo correcto? Necesito hacer esta verificación para avisar al usuario antes de tomar cualquier medida para crear una nueva alarma.


44
Valide la respuesta que resolvió su problema o publique su propia solución.
Anis

Respuestas:


322

Siguiendo el comentario que ron publicó, aquí está la solución detallada. Digamos que ha registrado una alarma repetitiva con una intención pendiente como esta:

Intent intent = new Intent("com.my.package.MY_UNIQUE_ACTION");
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, 
                                      intent, PendingIntent.FLAG_UPDATE_CURRENT);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add(Calendar.MINUTE, 1);

AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), 1000 * 60, pendingIntent);

La forma en que verificaría si está activa es:

boolean alarmUp = (PendingIntent.getBroadcast(context, 0, 
        new Intent("com.my.package.MY_UNIQUE_ACTION"), 
        PendingIntent.FLAG_NO_CREATE) != null);

if (alarmUp)
{
    Log.d("myTag", "Alarm is already active");
}

La clave aquí es la FLAG_NO_CREATEque, como se describe en el javadoc: if the described PendingIntent **does not** already exists, then simply return null(en lugar de crear una nueva)


99
¿Tiene que usar la intención solo con una cadena de acción? Intenté especificar una clase, nueva intención (contexto, MyClass.class) pero parece que no funciona. Siempre devuelve nulo incluso cuando la alarma está funcionando.
toc777

55
toc777, no, debe ser una cadena que coincida con una acción declarada en su filtro de intención en su manifiesto.xml
Chris Knight

44
Chris, era otro problema que estaba causando mi problema. La intención que mencioné anteriormente realmente funciona :)
toc777

41
Tenga en cuenta que deberá llamar a ambos alarmManager.cancel(pendingIntent)y pendingIntent.cancel()para que esta solución devuelva falso.
Kevin Cooper

26
En caso de que no sea obvio, el código en esta respuesta no verifica que la intención pendiente se haya registrado con el administrador de alarmas. El código simplemente verifica que el PendingIntent se creó a través de getBroadcast con una intención de destino equivalente. Puede probar esto ejecutando el código alarmUp después de getBroadcast all, pero antes de todo el calendario y el administrador de alarmas. Volverá cierto. Este hecho explica por qué debe utilizar PendingIntent.cancel para obtener el valor para volver a falso. Estrictamente hablando, esto no responde la pregunta.
bigh_29

114

Para otros que puedan necesitar esto, aquí hay una respuesta.

Utilizar adb shell dumpsys alarm

Puede saber que la alarma se ha configurado y cuándo van a alarmarse e intervalo. También cuántas veces se ha invocado esta alarma.


36
No es realmente una respuesta programática para el OP, sino un consejo genial. Muy bueno saberlo.
JustSomeGuy

2
agregue un grep para filtrar la larga lista de alarmas: adb shell dumpsys alarm | grep <e.g. package name of your app>también funciona en los nuevos sistemas Windows (uso Win10)
muetzenflo

3
grep se ejecuta en el dispositivo móvil, no en su PC. Entonces, si grep funciona depende del sistema operativo Android. Los teléfonos más antiguos no vienen con grep.
Henning

53

Ejemplo de trabajo con receptor (la respuesta principal fue solo con acción).

//starting
AlarmManager alarmManager = (AlarmManager) getActivity().getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(getActivity(), MyReceiver.class);
intent.setAction(MyReceiver.ACTION_ALARM_RECEIVER);//my custom string action name
PendingIntent pendingIntent = PendingIntent.getBroadcast(getActivity(), 1001, intent, PendingIntent.FLAG_CANCEL_CURRENT);//used unique ID as 1001
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), aroundInterval, pendingIntent);//first start will start asap

//and stopping
Intent intent = new Intent(getActivity(), MyReceiver.class);//the same as up
intent.setAction(MyReceiver.ACTION_ALARM_RECEIVER);//the same as up
PendingIntent pendingIntent = PendingIntent.getBroadcast(getActivity(), 1001, intent, PendingIntent.FLAG_CANCEL_CURRENT);//the same as up
alarmManager.cancel(pendingIntent);//important
pendingIntent.cancel();//important

//checking if alarm is working with pendingIntent
Intent intent = new Intent(getActivity(), MyReceiver.class);//the same as up
intent.setAction(MyReceiver.ACTION_ALARM_RECEIVER);//the same as up
boolean isWorking = (PendingIntent.getBroadcast(getActivity(), 1001, intent, PendingIntent.FLAG_NO_CREATE) != null);//just changed the flag
Log.d(TAG, "alarm is " + (isWorking ? "" : "not") + " working...");

Vale la pena mencionar:

Si la aplicación de creación posterior (proceso) recupera el mismo tipo de PendingIntent (misma operación , mismo Intent - acción, datos, categorías, componentes, indicadores ), recibirá un PendingIntent que representa el mismo token si aún es válido, y por lo tanto, puede llamar a cancel () para eliminarlo.

En resumen, su PendingIntent debe tener las mismas características (operación y estructura de la intención) para controlarlo.


1
No estoy seguro de que esto sea suficiente. En el caso de que un PendingIntent se registre con AlarmManager y luego se detenga con ambos métodos de cancelación, 'isWorking' anterior seguirá siendo cierto. El PendingIntent parece no haberse eliminado de AlarmManager y seguirá devolviendo una instancia. ¿Cómo podemos saber efectivamente cuándo se han activado / desactivado las alarmas?
johnDisplayClass

Esto realmente funcionó perfectamente. Cosas a tener en cuenta: setAction () y requestCode () deben ser idénticos en todos los getBroadcast () y vale la pena desinstalar la aplicación de su dispositivo. Eso me atrapó. Gracias
johnDisplayClass

Funciona genial. ¡Gracias!
Ambran

1
Buen ejemplo, pero no usaría 1001 como código de solicitud privado allí. Solo 0 para hacer el ejemplo más obvio.
Chris

1
Abstenerse de utilizar "respuesta principal", etc. En su lugar, proporcione un enlace a la respuesta. Porque las respuestas pueden cambiar las posiciones en la página según la popularidad.
Kathir

44

Tenga en cuenta esta cita de los documentos para el método establecido de Alarm Manager:

Si ya hay una alarma programada para este Intento (con la igualdad de dos intentos definidos por Intent.filterEquals), se eliminará y se reemplazará por este.

Si sabe que desea configurar la alarma, no necesita molestarse en verificar si ya existe o no. Simplemente créelo cada vez que se inicie su aplicación. Reemplazará cualquier alarma pasada con la misma Intent.

Necesita un enfoque diferente si está tratando de calcular cuánto tiempo le queda a una alarma creada previamente, o si realmente necesita saber si tal alarma existe. Para responder esas preguntas, considere guardar los datos de preferencias compartidas al momento de crear la alarma. Puede almacenar la marca de tiempo del reloj en el momento en que se activó la alarma, la hora en que espera que suene la alarma y el período de repetición (si configura una alarma que se repite).


2
En mi opinión, esta debería ser la respuesta aceptada. A menos que el OP tenga una situación especial que justifique no reiniciar la alarma
Jose_GD

En mi caso, quiero saber si la alarma ya está configurada y, de ser así, no quiero crear una nueva o restablecer la alarma existente.
Imran Aslam

2
Excelente respuesta. ¿Por qué el OP no verificó esto en absoluto? No hay nada que necesites hacer.
Vijay Kumar Kanta

2
Hay muchos agujeros de bucle en esta solución, esto puede anular el tiempo de alarma creado previamente (digamos si el tiempo necesita especificarse como t + 24), por lo que cada vez que se inicia la aplicación, el tiempo de alarma sigue avanzando un estado que nunca podría obtener se dispara para muchos, por lo que verificar la alarma si ya existe es más confiable
Naga

10

Tengo 2 alarmas Estoy usando la intención con extras en lugar de acción para identificar los eventos:

Intent i = new Intent(context, AppReciever.class);
i.putExtra("timer", "timer1");

La cosa es que con los extras extras la intención (y la alarma) no será única. Entonces, para poder identificar qué alarma está activa o no, tuve que definir diff requestCode-s:

boolean alarmUp = (PendingIntent.getBroadcast(context, MyApp.TIMER_1, i, 
                    PendingIntent.FLAG_NO_CREATE) != null);

y así es como se creó la alarma:

public static final int TIMER_1 = 1;
public static final int TIMER_2 = 2;

PendingIntent pending = PendingIntent.getBroadcast(context, TIMER_1, i,
            PendingIntent.FLAG_CANCEL_CURRENT);
setInexactRepeating(AlarmManager.RTC_WAKEUP,
            cal.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pending);
pending = PendingIntent.getBroadcast(context, TIMER_2, i,
            PendingIntent.FLAG_CANCEL_CURRENT);
setInexactRepeating(AlarmManager.RTC_WAKEUP,
            cal.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pending);

Usar las intenciones extras y esta solución me funcionó. Solo un cambio es que estoy usando el servicio, así que lo he cambiado aPendingIntent.getService
Pankaj

8

Acabo de encontrar otra solución, parece funcionar para mí

Intent myIntent = new Intent(MainActivity.this, MyReceiver.class);

boolean isWorking = (PendingIntent.getBroadcast(MainActivity.this, 0, myIntent, PendingIntent.FLAG_NO_CREATE) != null);
if (isWorking) {Log.d("alarm", "is working");} else {Log.d("alarm", "is not working");}

if(!isWorking) {
    pendingIntent = PendingIntent.getBroadcast(MainActivity.this, 0, myIntent,    PendingIntent.FLAG_UPDATE_CURRENT);
    alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
    int timeNotif = 5 * 60 * 1000;//time in ms, 7*24*60*60*1000 for 1 week
    Log.d("Notif", "Notification every (ms): " + timeNotif);
    alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), timeNotif, pendingIntent);
    }

A veces, en Marshmallow, después de forzar la detención de una aplicación, getBroadcast () devolverá no nulo, pero la alarma no está configurada.
hopia

6

Mientras que casi todos aquí han dado la respuesta correcta, ningún cuerpo explicó sobre qué base funcionan las alarmas

De hecho, puede obtener más información sobre AlarmManagersu funcionamiento aquí . Pero aquí está la respuesta rápida.

Usted ve AlarmManagerbásicamente horarios PendingIntenten algún momento en el futuro. Entonces, para cancelar la alarma programada, debe cancelarla PendingIntent.

Siempre tenga en cuenta dos cosas al crear el PendingIntent

PendingIntent.getBroadcast(context,REQUEST_CODE,intent, PendingIntent.FLAG_UPDATE_CURRENT);
  • Código de solicitud: actúa como el identificador único
  • Indicador: define el comportamiento de PendingIntent

Ahora, para verificar si la alarma ya está programada o para cancelarla, solo necesita tener acceso a la misma PendingIntent. Esto se puede hacer si usa el mismo código de solicitud y usa FLAG_NO_CREATEcomo se muestra a continuación

PendingIntent pendingIntent=PendingIntent.getBroadcast(this,REQUEST_CODE,intent,PendingIntent.FLAG_NO_CREATE);

if (pendingIntent!=null)
   alarmManager.cancel(pendingIntent);

Con FLAG_NO_CREATEél volverá nullsi el PendingIntentya no existe. Si ya existe, devuelve referencia a la existentePendingIntent


Si el código de solicitud es un identificador, ¿es importante pasar la intención con la acción correspondiente?
Sekula1991

¿Hay alguna manera de obtener la hora en que se programó la alarma con el administrador de alarmas si tiene la intención pendiente?
M. Smith

4

Hice un script bash simple (estúpido o no), que extrae los largos del adb shell, los convierte en marcas de tiempo y lo muestra en rojo.

echo "Please set a search filter"
read search

adb shell dumpsys alarm | grep $search | (while read i; do echo $i; _DT=$(echo $i | grep -Eo 'when\s+([0-9]{10})' | tr -d '[[:alpha:][:space:]]'); if [ $_DT ]; then echo -e "\e[31m$(date -d @$_DT)\e[0m"; fi; done;)

intentalo ;)


1
    Intent intent = new Intent("com.my.package.MY_UNIQUE_ACTION");
            PendingIntent pendingIntent = PendingIntent.getBroadcast(
                    sqlitewraper.context, 0, intent,
                    PendingIntent.FLAG_NO_CREATE);

FLAG_NO_CREATE no crea una intención pendiente, por lo que da un valor booleano falso.

            boolean alarmUp = (PendingIntent.getBroadcast(sqlitewraper.context, 0,
                    new Intent("com.my.package.MY_UNIQUE_ACTION"),
                    PendingIntent.FLAG_NO_CREATE) != null);

            if (alarmUp) {
                System.out.print("k");

            }

            AlarmManager alarmManager = (AlarmManager) sqlitewraper.context
                    .getSystemService(Context.ALARM_SERVICE);
            alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
                    System.currentTimeMillis(), 1000 * 60, pendingIntent);

Después de que el AlarmManager verifique el valor de Intento pendiente, da verdadero porque AlarmManager actualiza el indicador de intención pendiente.

            boolean alarmUp1 = (PendingIntent.getBroadcast(sqlitewraper.context, 0,
                    new Intent("com.my.package.MY_UNIQUE_ACTION"),
                    PendingIntent.FLAG_UPDATE_CURRENT) != null);
            if (alarmUp1) {
                System.out.print("k");

            }

0

Tengo la impresión de que no hay forma de hacer esto, sin embargo, sería bueno.

Puede lograr un resultado similar haciendo que se grabe un Alarm_last_set_time en alguna parte y teniendo un On_boot_starter BroadcastReciever: BOOT_COMPLETED algo así.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.