AlarmManager 在请求时未触发

Posted

技术标签:

【中文标题】AlarmManager 在请求时未触发【英文标题】:AlarmManager not firing when requested 【发布时间】:2015-03-11 23:24:34 【问题描述】:

所以我制作了一个应该在每周三早上 8:15 发送通知的应用。我正在使用 AlarmManager 从日历日期发送不准确的重复警报,以打开发送通知的待处理意图。

目前的情况是,仅当您首次下载应用时才会发送通知。今天早上它并没有像我自己或我的任何用户那样发生。我想知道 AlarmManager 是否安排在第一个通知触发后一周(即第一次下载应用程序后一周)?

这是我在 MainActivity 中的 manageNotifications 方法:

public void manageNotifications() 

    alarmManager = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
    alarmIntent = new Intent(this, AlarmReceiver.class);
    pendingIntent = PendingIntent.getBroadcast(this, 0, alarmIntent, PendingIntent.FLAG_CANCEL_CURRENT);
    calendar = java.util.Calendar.getInstance();

    calendar.setTimeInMillis(System.currentTimeMillis());
    calendar.set(java.util.Calendar.DAY_OF_WEEK, java.util.Calendar.WEDNESDAY);
    calendar.set(java.util.Calendar.HOUR_OF_DAY, 8);
    calendar.set(java.util.Calendar.MINUTE, 15);

    /*
    sets alarm manager to go off at 8:15 in the morning every 7 days on Wednesday
     */
    alarmManager.setInexactRepeating(AlarmManager.RTC, calendar.getTimeInMillis(), 1000 * 60 * 60 * 24 * 7, pendingIntent);
//end manageNotifications

这是挂起的意图调用的我的 AlarmReceiver:

公共类 AlarmReceiver 扩展 BroadcastReceiver

NotificationCompat.Builder notificationBuilder;
Intent notificationResultIntent;
ArrayList<Show> shows;
SharedPreferences spSpreadsheets, spNotifications;
final String showSpreadsheetURL = "https://docs.google.com/spreadsheets/d/1Ax2-gUY33i_pRHZIwR8AULy6-nbnAbM8Qm5-CGISevc/gviz/tq";

public void onReceive(Context context, Intent intent) 
    System.out.println("AlarmReceiver created");
    spNotifications = context.getSharedPreferences("notificationToggle", Context.MODE_PRIVATE);
    spSpreadsheets = context.getSharedPreferences("spreadsheets", Context.MODE_PRIVATE);

    if (spNotifications.getBoolean("notifications", false)) 
        int nextRegularShowIndex = 0, i = 0;

        shows = new ArrayList<>();

        try 
            if (spSpreadsheets.getString("showsSpreadsheet", "").equals(""))
                getShows(context);
            shows = processShowsJson(new JSONObject(spSpreadsheets.getString("showsSpreadsheet", "")));

            while (shows.get(i).getShowTime() != 0) 
            /*
            checks for first instance of a regular showtime
             */
                i++;
                nextRegularShowIndex = i;
            
            checkForPastShows();
            notificationBuilder = new NotificationCompat.Builder(context)
                    .setSmallIcon(R.drawable.applogo)
                    .setContentTitle("Comedy Club of Jacksonville")
                    .setContentText(shows.get(nextRegularShowIndex).getComedian() + " headlines this weekend at the Comedy " +
                            "Club of Jacksonville.  Click to read more.")
                    .setDefaults(Notification.DEFAULT_ALL);
            notificationResultIntent = new Intent(context, ThisWeekendFromNotification.class).putParcelableArrayListExtra("shows", shows);

            TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
            stackBuilder.addParentStack(ThisWeekend.class);
            stackBuilder.addNextIntent(notificationResultIntent);
            PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
            notificationBuilder.setContentIntent(resultPendingIntent);
            notificationBuilder.setAutoCancel(true);
            NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
            mNotificationManager.notify(0, notificationBuilder.build());
            System.out.println("Notification built");

         catch (Exception e) 
            e.printStackTrace();
        //end onReceive
    

这是我的 BootReceiver 类,用于在手机重启时重置警报:

public class BootReceiver extends BroadcastReceiver 
@Override
public void onReceive(Context context, Intent intent) 
    if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) 
        java.util.Calendar calendar = java.util.Calendar.getInstance();
        AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        Intent alarmIntent = new Intent(context, AlarmReceiver.class);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, alarmIntent, PendingIntent.FLAG_CANCEL_CURRENT);

        calendar.setTimeInMillis(System.currentTimeMillis());
        calendar.set(java.util.Calendar.DAY_OF_WEEK, java.util.Calendar.WEDNESDAY);
        calendar.set(java.util.Calendar.HOUR_OF_DAY, 8);
        calendar.set(java.util.Calendar.MINUTE, 15);

    /*
    sets alarm manager to go off at 8:15 in the morning every 7 days on Wednesday
     */
        alarmManager.setInexactRepeating(AlarmManager.RTC, calendar.getTimeInMillis(), 1000 * 60 * 60 * 24 * 7, pendingIntent);
    

【问题讨论】:

在使用setInexactRepeating(...)时尝试AlarmManager.RTC_WAKEUP 【参考方案1】:

首先,您使用的是setInexactRepeating()。除非您的 minSdkVersion 为 19 或更高,否则您不能将 setInexactRepeating() 与任意句点一起使用。

其次,setInexactRepeating() 不准确。您的闹钟不会在星期三上午 8:15 响起。它会在某个时候熄灭。引用the JavaDocs:

您的警报的第一次触发不会在请求的时间之前,但它可能不会在该时间之后的几乎整个间隔内发生。

第三,正如 Squonk 在评论中指出的那样,您使用 RTC 作为警报类型。您的闹钟将进一步延迟,直到设备因其他原因唤醒。

如果您的targetSdkVersion 低于 19,您可以使用setRepeating() 进行精确的重复警报。否则,使用set()(API 级别 19 之前)和setExact()(API 级别 19+)来安排您的警报,并在警报响起时安排下一个警报作为完成工作的一部分。此外,如果您想将设备从睡眠模式唤醒以完成工作,请使用 RTC_WAKEUP

【讨论】:

我将 minSdkVersion 设置为 19。我不知道不精确的重复可能直到几乎一个完整的间隔才会触发......我肯定会改变它。通过仿真器测试,它似乎是一致的,它会在预定时间的几分钟内触发。最后,使用带有 setRepeating 的 RTC_WAKEUP 可能会更好。谢谢你们。

以上是关于AlarmManager 在请求时未触发的主要内容,如果未能解决你的问题,请参考以下文章

android alarmmanager如果设置过去的时间就会触发广播?

24 AlarmManagerService机制

Android_AlarmManager(全局定时器)

alarmManager 设置警报以在准确时间而不是分数工作

从 Activity 外部调用 startActivity()?

Android中Alarm的机制