问题描述
我正在尝试创建一个基于警报的应用程序。我正在使用 AlarmManager
。问题是它根本不可靠。在某些设备中它可以工作..在其他设备中它可以运行thimes ..在其他设备中它根本不工作。
I'm trying to create an alarm based application. I'm using AlarmManager
. The thing is that it's not reliable at all. In some devices it works.. in other devices it works somethimes.. and in other devices it doesn't work at all.
当我说它不起作用时简单来说,警报不会触发。例如,在我的小米Mi4中,如果关闭屏幕,则不会发出警报。
我正在测试Moto G,在这种情况下,手机闹钟可以正常工作,但是在OnePlus中,闹钟也不会触发。他们只是从来没有被叫过。
When I say that it doesn't work is that simply, alarms won't fire. For example, in my Xiaomi Mi4, if you turn off the screen, no alarm will fire.I have a testing Moto G and in that phone alarms use to work fine, but in OnePlus, alarms won't fire too. They simply are never called.
我错过了什么吗?有人知道我在做什么错吗?
Am I missing something? Does anybody know what am I doing wrong??
非常感谢您的帮助!
这是我的警报类:
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);
}
}
这是我的OneTimeAlarm,提醒仅触发一次,然后不再触发。
This is my OneTimeAlarm, alarm that fires just once and then it doesn't fire again.
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);
}
}
这是我的日常警报,仅触发一次警报
This is my daily alarm, alarm that fires just once a day.
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);
}
}
这是我重复出现的警报,每次触发时都会触发
This is my repeating alarm, an alarm that fires every hour.
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);
}
}
我的WakeLocker类(我在stackoverflow上找到了它)
My WakeLocker class (i found it here at 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;
}
}
最后,是我的清单。
<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>
例如,这就是我在活动中设置警报的方式。
And this is how I set alarms, for example, inside of an activity.
AlarmaDiaria alarma = new AlarmaDiaria();
alarma.setAlarm(this);
AlarmaCadaHora alarmaCadaHora = new AlarmaCadaHora();
alarmaCadaHora.setAlarm(this);
推荐答案
除了marcin的答案外,另一个原因可能是建立任务管理器/能源管理器。如果编写,则警报在某些设备上可以正常工作,而在某些设备上则不能,这可能是由于Marcin建议的API较低/较高。但是,我在华为Ascend Mate 7上探索了另一件事:有些设备内部装有能源控制系统,该系统会在屏幕关闭后直接完全关闭应用程序。我的一个带有警报管理器的应用程序也遇到了同样的问题,并且没有任何帮助,无论是常规服务,前台服务还是任何其他编程解决方案。这很简单:我必须进入设置->节能模式->受保护的应用程序
。在这里,您必须启用对应用程序的保护。
In addition to marcin´s answer, another reason could be a build in task-manager/energy-manager. If you write, your alarm works fine on some devices and in some not, it could be because of lower/higher APIs like Marcin suggested. But there is another thing that I have explored on my Huawei Ascend Mate 7: Some devices have an energy control system inside that directly closes the application completely after screen goes off. I had the same problem with one of my apps with an alarm manager and nothing helped, wether a usual service nor a foreground service nor any other programming solution. It was just simple: I had to go to settings-->energy saving mode-->protected apps
. Here you have to enable the protection of your app.
在您的情况下,这可能不是解决方案,但是在其他许多设备中,解决方案太长了,无法发表评论,因此我不得不提出作为答案。
It may be that this is not the solution in Your case, but it is in much other devices and this explanation is too long for a comment, so I have to put it as answer.
这篇关于AlarmManager无法正常工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!