手机复位后AlarmManager报警不触发

Posted

技术标签:

【中文标题】手机复位后AlarmManager报警不触发【英文标题】:AlarmManager alarm does not trigger after the phone resets 【发布时间】:2014-10-10 09:34:41 【问题描述】:

在我的应用程序中,用户加入了一个计划,然后第二天中午会有一个警报通知。这是我的代码:

首先,我在 AlarmManager 中设置了一个闹钟,如下所示:

//set alarm to the next day 12:00 noon of the join date
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");  
try   
    alarm_date = format.parse(join_date);
 catch (ParseException e)   
    e.printStackTrace();  


GregorianCalendar calender = new GregorianCalendar();
calender.setTime(alarm_date);
calender.add(Calendar.DATE, 1);
calender.add(Calendar.HOUR_OF_DAY, 12);
//calender.add(Calendar.HOUR_OF_DAY, 14); //temp testing data
//calender.add(Calendar.MINUTE, 43);

AlarmManager am = (AlarmManager) ctx.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(ctx, AlarmReceiver.class);
am.set(AlarmManager.RTC_WAKEUP, calender.getTimeInMillis(), PendingIntent.getBroadcast(ctx, 1, i, PendingIntent.FLAG_UPDATE_CURRENT));

然后,在预定的时间,它像这样触发接收器:

public class AlarmReceiver extends BroadcastReceiver 
    @Override
    public void onReceive(Context context, Intent intent) 
        Intent service = new Intent(context, AlarmService.class);
        context.startService(service);
    

最后,它调用服务来显示通知或将应用程序置于后台(如果它在后台)。这是代码:

public class AlarmService extends Service 
    private Context ctx;
    private MyApp gs;
    private SharedPreferences prefs;
    NotificationManager notificationManager;
    Notification myNotification;
    private String joinPlanID;
    private String joinPlanDate;
    private int period;

    public AlarmService() 
    

    @Override
    public IBinder onBind(Intent intent) 
        return null;
    

    public void checkPlanPeriod(String planID) 
        if (joinPlanID.equals("1"))
            period = 15;
        else if (joinPlanID.equals("2"))
            period = 30;
        else if (joinPlanID.equals("3"))
            period = 45;
    

    @Override
    public void onStart(Intent intent, int startId) 
        ctx = getApplicationContext();
        gs = (MyApp) getApplication();
        prefs = PreferenceManager.getDefaultSharedPreferences(ctx);

        if (prefs.getString("joinPlanID", null) != null) 
            Date alarmDate = null;
            joinPlanID = prefs.getString("joinPlanID", null);
            joinPlanDate = prefs.getString("joinPlanDate", null);
            checkPlanPeriod(joinPlanID);

            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");  
            try   
                alarmDate = format.parse(joinPlanDate);
             catch (ParseException e)   
                e.printStackTrace();  
            

            GregorianCalendar planCalendar = new GregorianCalendar();
            planCalendar.setTime(alarmDate);
            planCalendar.add(Calendar.DATE, period);

            Calendar now = Calendar.getInstance();
            now.add(Calendar.DATE, 1);

            Calendar tomorrowAlarm = Calendar.getInstance();
            tomorrowAlarm.set(Calendar.YEAR, now.get(Calendar.YEAR));
            tomorrowAlarm.set(Calendar.MONTH, now.get(Calendar.MONTH));
            tomorrowAlarm.set(Calendar.DAY_OF_MONTH, now.get(Calendar.DAY_OF_MONTH));
            tomorrowAlarm.set(Calendar.HOUR_OF_DAY, 12);
            tomorrowAlarm.set(Calendar.MINUTE, 0);
            tomorrowAlarm.set(Calendar.SECOND, 0);
            tomorrowAlarm.set(Calendar.MILLISECOND, 0);

            if (planCalendar.compareTo(tomorrowAlarm) != -1) 
                //set the next day alarm
                AlarmManager am = (AlarmManager) ctx.getSystemService(Context.ALARM_SERVICE);
                Intent i = new Intent(ctx, AlarmReceiver.class);
                am.set(AlarmManager.RTC_WAKEUP, tomorrowAlarm.getTimeInMillis(), PendingIntent.getBroadcast(ctx, 1, i, PendingIntent.FLAG_UPDATE_CURRENT));
            
        

        if (gs.getIsAppStart()) 
             Intent dialogIntent = new Intent(this, Main.class);
             dialogIntent.putExtra("is_remind", true);
             dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
             this.startActivity(dialogIntent);
         else 
            NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(ctx)
            .setSmallIcon(R.drawable.ic_launcher)
            .setContentTitle(getResources().getString(R.string.notify_title))
            .setContentText(getResources().getString(R.string.notify_msg));

            Intent toLaunch = new Intent(getApplicationContext(), Main.class);
            toLaunch.putExtra("is_remind", true);
            toLaunch.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
            PendingIntent intentBack = PendingIntent.getActivity(ctx, 0, toLaunch,PendingIntent.FLAG_UPDATE_CURRENT);

            mBuilder.setContentIntent(intentBack);
            NotificationManager mNotificationManager = (NotificationManager) ctx.getSystemService(Context.NOTIFICATION_SERVICE);

            // Send Notification
            Notification primaryNotification = mBuilder.build();
            mNotificationManager.notify(10001, primaryNotification);
        

    

问题是,如果我重置我的设备,它既不会触发警报,我的接收器也不会收到任何东西。我该如何解决?

【问题讨论】:

重置意味着?重启? 是的,该程序只有在我没有关闭应用程序/重启的情况下才有效。 你们都在清单、BroadCastReceiver 和 Service 中注册了吗?设置权限了吗? does Alarm Manager persist even after reboot? 这应该可以解决您的问题。 是的发现我需要创建一个接收器来恢复闹钟 【参考方案1】:

添加一个BootReceiver

public class BootReceiver extends BroadcastReceiver 

    private static final String BOOT_COMPLETED =
            "android.intent.action.BOOT_COMPLETED";
    private static final String QUICKBOOT_POWERON =
            "android.intent.action.QUICKBOOT_POWERON";

    @Override
    public void onReceive(Context context, Intent intent) 
        String action = intent.getAction();
        if (action.equals(BOOT_COMPLETED) ||
                action.equals(QUICKBOOT_POWERON)) 
            Intent service = new Intent(context, BootService.class);
            context.startService(service);
        
    


添加一个BootService

public class BootService extends IntentService 

    public BootService() 
        super("BootService");
    

    private void setAlarm() 
        // Set your alarm here as you do in "1. First I set an alarm in alarm manager"
    

    private void setAlarmsFromDatabase() 
        // Set your alarms from database here
    

    @Override
    protected void onHandleIntent(Intent intent) 
        setAlarm();
        setAlarmsFromDatabase(); // A nice a approach is to store alarms on a database, you may not need it
        Intent service = new Intent(this, BootService.class);
        stopService(service);
    


然后在你的AndroidManifest.xml 添加

<receiver android:name=".BootReceiver"
          android:enabled="true">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED"/>
         <action android:name="android.intent.action.QUICKBOOT_POWERON" />
    </intent-filter>
</receiver>
<service android:name=".BootService"
         android:enabled="true"/>

并且还要添加这个权限

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

现在您可以重新启动设备,每次设备启动时都会设置闹钟

【讨论】:

【参考方案2】:

手机重启后所有设置的闹钟都会被清除。要使警报意图起作用,您需要创建一个待处理的意图并将其设置在警报管理器中。您可以使用数据库存储警报详细信息并在手机启动时重新创建警报。 (应用程序应该监听 android.intent.action.BOOT_COMPLETED)

【讨论】:

如果警报还没有触发,如果我再次重启,它会替换旧的还是重复的?谢谢 所有警报在重启时被清除。因此,在重新启动时创建一个相同的警报将是解决方案。【参考方案3】:

由于您正在启动服务,因此设备可能会唤醒以运行警报运行 onReceive 方法,然后在启动服务之前返回睡眠状态,通常是从 @987654322 启动服务时@ 你应该改用 WakefulBroadcastReceiver 为你处理唤醒锁,试试看是否有帮助,即使它没有帮助你也应该使用它

【讨论】:

以上是关于手机复位后AlarmManager报警不触发的主要内容,如果未能解决你的问题,请参考以下文章

带有BroadcastReceiver的报警管理器

NO---22 H5在ios端微信浏览器中,input事件触发后页面不复位的问题

AlarmManager 在错误的时间触发警报

AlarmManager 在请求时未触发

Android AlarmManager 一小时后触发

终止应用程序后未触发 AlarmManager 通知