Android每日闹钟触发太频繁或只触发一次

时间:2014-01-23 17:39:52

标签: android alarmmanager

我正在尝试在我的Android应用中实现“每日提醒”功能,该功能应该在设定的时间每天触发一次。我试过的第一个实现适用于大多数人,但是一些用户子集(包括至少一个在三星的Android 4.3上运行的人)报告说警报更频繁地发出警告,例如:每10分钟,每次他们打开应用程序,一般都非常讨厌。

以下是警报的启用方式:

Intent myIntent = new Intent(ctx, AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(ctx, 0, myIntent,0);

AlarmManager alarmManager = (AlarmManager)ctx.getSystemService(Service.ALARM_SERVICE);
alarmManager.cancel(pendingIntent);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, sched, 
                AlarmManager.INTERVAL_DAY, 
                pendingIntent);

然后就是这个AlarmReceiver类:

public class AlarmReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        // TODO Auto-generated method stub

           Intent service1 = new Intent(context, AlarmService.class);
           context.startService(service1);
    }

}

这是在AndroidManifest中注册为接收者:<receiver android:name=".AlarmReceiver"/>

最后是AlarmService,过去看起来像这样:

public class AlarmService extends Service { 

    @Override
    public IBinder onBind(Intent arg0) {
        // TODO Auto-generated method stub
        return null;
    }


    @Override
    public void onCreate() 
    {
       // TODO Auto-generated method stub  
       super.onCreate();
    }

   @SuppressWarnings("static-access")
   @Override
   public void onStart(Intent intent, int startId)
   {
       super.onStart(intent, startId);

       Log.v("pm", "about to notify");

       Intent intent1 = new Intent(this.getApplicationContext(), MainActivity.class);
       intent1.setAction(Intent.ACTION_MAIN);
       intent1.addCategory(Intent.CATEGORY_LAUNCHER);
       //intent1.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP| Intent.FLAG_ACTIVITY_CLEAR_TOP);

       PendingIntent pendingNotificationIntent = PendingIntent.getActivity( this.getApplicationContext(),0, intent1,PendingIntent.FLAG_UPDATE_CURRENT);

       Notification notification = new Notification.Builder(this.getApplicationContext())
                                       .setContentTitle("My App")
                                       .setContentText("Don't forget that thing!")
                                       .setSmallIcon(R.drawable.ic_launcher)
                                       .setWhen(System.currentTimeMillis())
                                       .setContentIntent(pendingNotificationIntent)
                                       .getNotification();                     

       notification.flags |= Notification.FLAG_AUTO_CANCEL;
       notification.defaults |= Notification.DEFAULT_SOUND;
       notification.defaults |= Notification.DEFAULT_VIBRATE;

       NotificationManager nManager = 
                (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
       nManager.notify(0, notification);
    }

    @Override
    public void onDestroy() 
    {
        // TODO Auto-generated method stub
        super.onDestroy();
    }
}

然而,正如我所说,人们报告说这每十分钟左右开枪一次!所以我尝试将AlarmService更改为较少弃用的实现,但是在这个过程中,现在人们说它只会触发一次,然后再也不会了!

我将onStart替换为:

 @Override
 public int onStartCommand(Intent intent, int flags, int startId)
 {
       Log.v("pm", "about to notify");

   if (intent != null) {
       Intent intent1 = new Intent(this.getApplicationContext(), MainActivity.class);
       intent1.setAction(Intent.ACTION_MAIN);
       intent1.addCategory(Intent.CATEGORY_LAUNCHER);
       //intent1.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP| Intent.FLAG_ACTIVITY_CLEAR_TOP);

       PendingIntent pendingNotificationIntent = PendingIntent.getActivity( this.getApplicationContext(),0, intent1,PendingIntent.FLAG_UPDATE_CURRENT);

       Notification notification = new Notification.Builder(this.getApplicationContext())
                                       .setContentTitle("My App")
                                       .setContentText("Don't forget that thing!")
                                       .setSmallIcon(R.drawable.ic_launcher)
                                       .setWhen(System.currentTimeMillis())
                                       .setContentIntent(pendingNotificationIntent)
                                       .getNotification();                     

       notification.flags |= Notification.FLAG_AUTO_CANCEL;
       notification.defaults |= Notification.DEFAULT_SOUND;
       notification.defaults |= Notification.DEFAULT_VIBRATE;

       NotificationManager nManager = 
                (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
       nManager.notify(0, notification);
   } else {
       Log.v("pm", "Null Intent");
   }

   return START_STICKY;
}

由于我无法在设备上重现原始问题,因此测试起来有点困难!我的两个理论是:

  1. 问题在于AlarmReceiver,就像它不应该启动一项全新的服务,而是使用现有服务做一些事情
  2. 我不应该在我的intent函数
  3. 中排除null onStartCommand

    如果它导致人们的设备再次惹恼他们,我会有点紧张尝试2号!

2 个答案:

答案 0 :(得分:6)

  

以下是警报的启用方式

请注意,即使您使用setRepeating(),一旦将android:targetSdkVersion提高到19或更高,这在Android 4.4+上也会不准确。

  

然后就是这个AlarmReceiver类

_WAKEUP式警报不可靠。设备在startService()通话和您的服务实际上有机会做某事之间入睡是非常有可能的。如果您要使用委托到服务模式,请use WakefulBroadcastReceivermy WakefulIntentService申请_WAKEUP式警报。

  

但是在这个过程中,现在人们说它每天只发射一次!

既然这就是你想要的,我认为这是件好事。

  

我将onStart替换为:

我不知道你为什么使用Service代替IntentService。无论如何,请致电stopSelf()方法底部的onStartCommand(),以免服务消失。完成此工作后,此服务没有理由继续运行。另外,将START_STICKY替换为START_NOT_STICKY

而且,如果这是您打算在服务中完成的所有工作,您可以完全转储服务并将onStartCommand()内容移至onReceive()的{​​{1}}。

当工作花费太长时间来冒着占用主应用程序线程的风险(例如,> 1ms)时,使用从接收器委托工作到服务的模式......但是那时你的服务需要一个后台线程,你缺少的。由于我希望您的代码在执行时间不到1毫秒,您可以在BroadcastReceiver中执行此操作并简化您的应用,您将不再需要单独的onReceive(),也不需要任何Service我前面提到过的东西。

  

问题在于AlarmReceiver,就像它不应该启动一项全新的服务,而是使用现有服务做一些事情

如果每天只运行一次,最好不要成为“现有服务”。没有必要让你有一个正在运行的进程,占用系统RAM,只是等待时钟滴答。

  

我不应该在我的onStartCommand函数

中排除null intent值

如果符合以下条件,您将获得Wakeful* null

  • 您的流程在服务完成Intent之前已终止onStartCommand()来电,

  • 您的服务之前已成功运行startService()并返回onStartCommand()

  

我越来越想知道为什么我的AlarmReceiver会创建服务,而不是直接显示通知。

同意。如果您计划进行更多工作,涉及磁盘或网络I / O,然后使用START_STICKY(后台线程,服务会自动停止)。否则,我只是把它放在IntentService中并称之为好。

答案 1 :(得分:0)

我只是想为所有遇到AlarmManager问题的人添加 Android 4.4 + ,添加stopSelf();是真的重要,就像@CommonsWave已经说过的那样,在服务中的onStartCommand()底部,从BroadcastReceiver调用