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.

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

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.

  • AlarmManager cuando el teléfono está apagado - ANDROID
  • Configuración de una alarma de repetición en android
  • Administrador de alarmas - Programación de varios eventos no repetitivos
  • ¿Cómo encuestar un webservice en el intervalo finito de androide?
  • ¿Dónde se utiliza el PendingIntent en AlarmManager.AlarmClockInfo?
  • Administrador de alarmas no funciona en segundo plano en Android 6.0
  • Cómo configurar Alarma para días laborables en android
  • Establecer la alarma de Android 4.4 Kitkat
  • Android Studio establece una alarma exacta con Icono
  • Actualizar un widget sólo cuando el dispositivo está activado Y el widget está visible en la pantalla de inicio
  • ¿Alarm Manager persiste incluso después del reinicio?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.