Android AlarmManager 在错误的时间触发警报
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21461191/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
AlarmManager fires alarms at wrong time
提问by Holger Jakobs
I managed everything all right to create a notification service used to fire a notification as a result of an alarm. Unfortunately, setting the alarm using AlarmManager doesn't work right. It fires several minutes later (not exactly hours, which would indicate a timezone problem). The recurring period is 1 week, so I used the constant INTERVAL_DAY and multiplied it with 7. In order to make sure that one PendingIntent doesn't replace the other, I pass the dayOfWeek as second parameter to PendingIntent.getService(). I check the correctness of the time for the alarm to fire by logging it:
我管理好一切以创建一个通知服务,用于根据警报发出通知。不幸的是,使用 AlarmManager 设置警报不起作用。它在几分钟后触发(不完全是几个小时,这表明时区问题)。重复周期为 1 周,因此我使用常量 INTERVAL_DAY 并将其乘以 7。为了确保一个 PendingIntent 不会替换另一个,我将 dayOfWeek 作为第二个参数传递给 PendingIntent.getService()。我通过记录来检查警报触发时间的正确性:
Log.d(TAG, "next alarm " + df.format(cal.getTime()));
Is there really no way to list all alarms set - at least those from my own app? I believe this is the only way to track down the error.
真的没有办法列出所有设置的警报 - 至少是我自己的应用程序中的警报吗?我相信这是追踪错误的唯一方法。
My code:
我的代码:
cal.setTimeInMillis(System.currentTimeMillis());
cal.add(Calendar.DATE, 1);
cal.set(Calendar.HOUR_OF_DAY, hour);
cal.set(Calendar.MINUTE, minute);
Log.d(TAG, "next alarm " + df.format(cal.getTime()));
Intent showNotificationIntent = new Intent(context, NotificationService.class);
dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
alarmIntent = PendingIntent.getService(context, dayOfWeek, showNotificationIntent, 0);
getAlarmManager(context).setInexactRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(),
INTERVAL_WEEK, alarmIntent);
I want to offer to have an alarm every day, but at various times, which can be set by the user. So I use up to 7 alarms, which should fire on a weekly basis.
我想提供每天都有一个闹钟,但在不同的时间,可以由用户设置。所以我最多使用 7 个闹钟,应该每周触发一次。
Even after reading the numerous answers to similar questions (I don't intend to create a duplicate question), I haven't managed to find the problem.
即使在阅读了类似问题的众多答案之后(我不打算创建重复的问题),我也没有找到问题所在。
回答by Blaz
For api levels below 19 you should use AlarmManager.setRepeating()
and your alarms will trigger exactly at specified time. Thou on api levels 19 and above this will no longer work. There was change in android so that all repeating alarms are inexact. So if you would like to achieve exact repeating alarm you should schedule alarm with AlarmManager.setExact()
and then when alarm triggers do it again for next week and so on every week.
对于低于 19 的 api 级别,您应该使用,AlarmManager.setRepeating()
并且您的警报将在指定时间准确触发。你在 19 级及以上的 api 级别将不再起作用。android 发生了变化,因此所有重复的警报都不准确。因此,如果您想实现精确的重复闹钟,您应该安排闹钟,AlarmManager.setExact()
然后在下周再次触发闹钟时再做一次,依此类推。
回答by Skynet
Because of setInexactRepeating. Use setRepeating and it will be processed at the right time.
因为 setInexactRepeating。使用 setRepeating 它将在正确的时间进行处理。
Instead of:
代替:
setInexactRepeating
use
用
setRepeating
setInexactRepeating, is OS and battery friendly, it batches together all the work to be done on Alarm receive and works through one by one, while as setRepeating instantly fires the alarm
setInexactRepeating,是操作系统和电池友好的,它将所有要在警报接收上完成的工作批处理在一起,并一一完成,而 setRepeating 会立即触发警报
Also a note: Alarms are wiped off once phone is rebooted, you might have to implement a boot broadcast receiver to make it persistent. Make sure you dont do that runtime, you need to implement it in the Manifest else when your app is not in background you will not receive any broadcasts.
另请注意:一旦手机重新启动,警报就会消失,您可能需要实现启动广播接收器以使其持久化。确保您不执行该运行时,您需要在清单中实现它,否则当您的应用程序不在后台时,您将不会收到任何广播。
A small example:
一个小例子:
This is working code. It wakes CPU every 10 minutes until the phone turns off.
这是工作代码。它每 10 分钟唤醒一次 CPU,直到手机关机。
Add to Manifest.xml:
添加到 Manifest.xml:
...
<uses-permission android:name="android.permission.WAKE_LOCK"></uses-permission>
...
<receiver android:process=":remote" android:name="Alarm"></receiver>
...
Code:
代码:
package YourPackage;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.PowerManager;
import android.widget.Toast;
public class Alarm extends BroadcastReceiver
{
@Override
public void onReceive(Context context, Intent intent)
{
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "");
wl.acquire();
// Put here YOUR code.
Toast.makeText(context, "Alarm !!!!!!!!!!", Toast.LENGTH_LONG).show(); // For example
wl.release();
}
public void SetAlarm(Context context)
{
AlarmManager am=(AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, Alarm.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 1000 * 60 * 10, pi); // Millisec * Second * Minute
}
public void CancelAlarm(Context context)
{
Intent intent = new Intent(context, Alarm.class);
PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent, 0);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(sender);
}
}
Set Alarm from Service:
从服务设置警报:
package YourPackage;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
public class YourService extends Service
{
Alarm alarm = new Alarm();
public void onCreate()
{
super.onCreate();
}
public void onStart(Context context,Intent intent, int startId)
{
alarm.SetAlarm(context);
}
@Override
public IBinder onBind(Intent intent)
{
return null;
}
}
If you want set alarm repeating at phone boot time:
如果您想在手机开机时设置闹钟重复:
Add permission to Manifest.xml:
向 Manifest.xml 添加权限:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"></uses-permission>
...
<receiver android:name=".AutoStart">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"></action>
</intent-filter>
</receiver>
...
And create new class:
并创建新类:
package YourPackage;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class AutoStart extends BroadcastReceiver
{
Alarm alarm = new Alarm();
@Override
public void onReceive(Context context, Intent intent)
{
if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED"))
{
alarm.SetAlarm(context);
}
}
}