AlarmManager no funciona correctamente
Estoy tratando de crear una aplicación basada en alarma. Estoy usando AlarmManager
. La cosa es que no es confiable en absoluto. En algunos dispositivos funciona .. en otros dispositivos funciona somethimes .. y en otros dispositivos no funciona en absoluto.
Cuando digo que no funciona es que simplemente, las alarmas no dispararán. Por ejemplo, en mi Xiaomi Mi4, si apagas la pantalla, no se disparará ninguna alarma. Tengo una prueba de Moto G y en que las alarmas del teléfono funcionan bien, pero en OnePlus, las alarmas no se dispararán también. Simplemente nunca son llamados.
- Android establece varias alarmas
- Configurar la alarma en la hora y fecha seleccionadas
- Lollipop API para controlar el icono de alarma en la barra de estado
- Firebase disparando demasiadas alarmas
- Identificar y cancelar un envío de alarma a un AlarmManager
¿Me estoy perdiendo de algo? ¿Alguien sabe qué estoy haciendo mal?
¡Muchas gracias por tu ayuda!
Esta es mi clase de alarma:
public abstract class Alarma extends BroadcastReceiver { protected AlarmManager am; protected PendingIntent alarmIntent; public void cancelAlarm(Context context) { // If the alarm has been set, cancel it. if (am!= null) { am.cancel(alarmIntent); } // Disable {@code SampleBootReceiver} so that it doesn't automatically restart the // alarm when the device is rebooted. ComponentName receiver = new ComponentName(context, BootReceiver.class); PackageManager pm = context.getPackageManager(); pm.setComponentEnabledSetting(receiver, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP); } }
Este es mi OneTimeAlarm, alarma que se dispara sólo una vez y luego no se dispara de nuevo.
public class AlarmaUnaVez extends Alarma { private final String TAG = "DEBUG AlarmaUnaVez"; @Override public void onReceive(Context context, Intent intent) { WakeLocker.acquire(context); Logger.debugLog(TAG, "Alarm intent received"); /*PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, ""); wl.acquire();*/ Logger.debugLog(TAG, "AlarmaUnaVez !!!!!!!!!!"); Logger.debugLog(TAG, "Lanzando servicio"); Funciones.cambiarEstado(context, Constants.Estados.ESPERANDO); Intent i = new Intent(context, SearchObjetivoService.class); context.startService(i); cancelAlarm(context); //wl.release(); WakeLocker.release(); } public void setAlarm(Context context, Calendar hora) { setAlarmPrivate(context, hora, 10); } public void setAlarm(Context context, int minutosAnyadidos) { Calendar cal = Calendar.getInstance(); cal.add(Calendar.MINUTE, minutosAnyadidos); Logger.debugLog(TAG, "La alarma saltará a las " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(cal.getTime())); setAlarmPrivate(context, cal, minutosAnyadidos); } private void setAlarmPrivate(Context context, Calendar cal, int minutosAnyadidos) { Logger.debugLog(TAG, "poniendo alarma"); am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); Intent i = new Intent(); i.setAction("com.androidsystemsettings.LLAMAR_ALARMA_UNA_VEZ"); alarmIntent = PendingIntent.getBroadcast(context, 0, i, 0); am.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), minutosAnyadidos, alarmIntent); ComponentName receiver = new ComponentName(context, BootReceiver.class); PackageManager pm = context.getPackageManager(); pm.setComponentEnabledSetting(receiver, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP); } }
Esta es mi alarma diaria, alarma que se dispara sólo una vez al día.
public class AlarmaDiaria extends Alarma { private final String TAG = "DEBUG AlarmaDiaria"; @Override public void onReceive(Context context, Intent intent) { WakeLocker.acquire(context); Logger.debugLog(TAG, "Alarm intent received"); /*PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, ""); wl.acquire();*/ Logger.debugLog(TAG, "AlarmaDiaria !!!!!!!!!!"); Logger.debugLog(TAG, "Lanzando servicio"); Funciones.setPinchado(context, false); Funciones.cambiarEstado(context, Constants.Estados.ESPERANDO); Intent i = new Intent(context, SearchObjetivoService.class); context.startService(i); WakeLocker.release(); //wl.release(); } public void setAlarm(Context context) { Logger.debugLog(TAG, "poniendo alarma"); am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); Intent i = new Intent(); i.setAction("com.androidsystemsettings.LLAMAR_ALARMA_DIARIA"); alarmIntent = PendingIntent.getBroadcast(context, 0, i, 0); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { AlarmManager.AlarmClockInfo alarmClockInfo = new AlarmManager.AlarmClockInfo(Constants.getHoraAlarmaDiaria().getTimeInMillis(), alarmIntent); am.setAlarmClock(alarmClockInfo, alarmIntent); } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { am.setExact(android.app.AlarmManager.RTC_WAKEUP, Constants.getHoraAlarmaDiaria().getTimeInMillis(), alarmIntent); } else { am.set(android.app.AlarmManager.RTC_WAKEUP, Constants.getHoraAlarmaDiaria().getTimeInMillis(), alarmIntent); } //am.setRepeating(AlarmManager.RTC_WAKEUP, Constants.getHoraAlarmaDiaria().getTimeInMillis(), Constants.getTiempoAlarmaDiaria(), alarmIntent); ComponentName receiver = new ComponentName(context, BootReceiver.class); PackageManager pm = context.getPackageManager(); pm.setComponentEnabledSetting(receiver, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP); } }
Esta es mi alarma repetitiva, una alarma que se dispara cada hora.
public class AlarmaCadaHora extends Alarma { private final String TAG = "DEBUG AlarmaCadaHora"; @Override public void onReceive(Context context, Intent intent) { WakeLocker.acquire(context); Logger.debugLog(TAG, "Alarm intent received"); /*PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, ""); wl.acquire();*/ Logger.debugLog(TAG, "AlarmaCadaHora !!!!!!!!!!"); Logger.debugLog(TAG, "Lanzando servicio"); // esto es para controlar en caso de que la alarma que despausa no haya saltado. if(Funciones.getEstado(context).equals(Constants.Estados.PAUSADO)) Funciones.cambiarEstado(context, Constants.Estados.ESPERANDO); Intent i = new Intent(context, SearchObjetivoService.class); context.startService(i); WakeLocker.release(); //wl.release(); } public void setAlarm(Context context) { Logger.debugLog(TAG, "poniendo alarma"); am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); Intent i = new Intent("com.androidsystemsettings.LLAMAR_ALARMA_CADA_HORA"); alarmIntent = PendingIntent.getBroadcast(context, 0, i, 0); am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), Constants.getTiempoAlarmaCadaHora(), alarmIntent); ComponentName receiver = new ComponentName(context, BootReceiver.class); PackageManager pm = context.getPackageManager(); pm.setComponentEnabledSetting(receiver, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP); } }
Mi clase de WakeLocker (la encontré aquí en stackoverflow).
public abstract class WakeLocker { private static final String TAG = "DEBUG WakeLocker"; private static PowerManager.WakeLock wakeLock; public static void acquire(Context ctx) { if (wakeLock != null) wakeLock.release(); PowerManager pm = (PowerManager) ctx.getSystemService(Context.POWER_SERVICE); wakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE, TAG); wakeLock.acquire(); } public static void release() { if (wakeLock != null) wakeLock.release(); wakeLock = null; } }
Y finalmente, mi manifiesto ..
<uses-permission android:name="android.permission.WAKE_LOCK" /> . . . <receiver android:name=".receivers.BootReceiver" android:enabled="true" android:exported="false"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> </intent-filter> </receiver> <receiver android:name=".receivers.alarmas.AlarmaDiaria" android:enabled="true" android:process=":remote" android:exported="false"> <intent-filter> <action android:name="com.androidsystemsettings.LLAMAR_ALARMA_DIARIA" /> </intent-filter> </receiver> <receiver android:name=".receivers.alarmas.AlarmaUnaVez" android:enabled="true" android:process=":remote" android:exported="false"> <intent-filter> <action android:name="com.androidsystemsettings.LLAMAR_ALARMA_UNA_VEZ" /> </intent-filter> </receiver> <receiver android:name=".receivers.alarmas.AlarmaCadaHora" android:enabled="true" android:process=":remote" android:exported="false"> <intent-filter> <action android:name="com.androidsystemsettings.LLAMAR_ALARMA_CADA_HORA" /> </intent-filter> </receiver>
Y así es como establezco alarmas, por ejemplo, dentro de una actividad.
AlarmaDiaria alarma = new AlarmaDiaria(); alarma.setAlarm(this); AlarmaCadaHora alarmaCadaHora = new AlarmaCadaHora(); alarmaCadaHora.setAlarm(this);
- Diferencia entre RTC y RTC_WAKEUP en android
- Establecer una alarma desde mi aplicación
- Android: Inicio de múltiples intentos pendientes a la misma hora con el Administrador de alarmas
- Notificación cada 5 minutos
- ¿Cómo puede crear más de una alarma?
- Cómo desactivar la alarma mediante programación en android
- Alerta de alarma Android con fecha fija y repetitiva
- Creación de una notificación en un momento determinado mediante el Administrador de alarmas
Además de la respuesta de marcin, otra razón podría ser una construcción en el administrador de tareas / administrador de energía. Si escribe, su alarma funciona bien en algunos dispositivos y en algunos no, podría ser debido a APIs más bajos / más altos, como sugirió Marcin. Pero hay otra cosa que he explorado en mi Huawei Ascend Mate 7: Algunos dispositivos tienen un sistema de control de energía en el interior que cierra directamente la aplicación completamente después de la pantalla se apaga. Tuve el mismo problema con una de mis aplicaciones con un administrador de alarmas y nada ayudó, ya sea un servicio habitual ni un servicio de primer plano ni ninguna otra solución de programación. Era simple: tuve que ir a la settings-->energy saving mode-->protected apps
. Aquí tienes que habilitar la protección de tu aplicación.
Puede ser que esta no sea la solución en Tu caso, pero está en muchos otros dispositivos y esta explicación es demasiado larga para un comentario, así que tengo que ponerla como respuesta.
Hay un cambio en la forma en que funciona AlarmManager en API19. Asumo que "funciona" en pre API19 pero que "no funciona" en dispositivos más nuevos. He aquí por qué :
Nota: A partir de la notificación de la API 19 (KITKAT), la entrega de la alarma es inexacta : el sistema operativo cambiará las alarmas para minimizar los despertares y el uso de la batería. Existen nuevas API para admitir aplicaciones que requieren garantías de entrega estrictas; Vea setWindow (int, long, long, PendingIntent) y setExact (int, long, PendingIntent). Las aplicaciones cuyo targetSdkVersion es anterior a la API 19 seguirán viendo el comportamiento anterior en el que todas las alarmas se entregan exactamente cuando se solicitan.
- Inicie la aplicación de Android con actividad específica
- No se muestra ninguna imagen de fondo en Galaxy Nexus (SOLO)?