安卓每日警报触发太频繁或只触发一次



我正在尝试在我的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. 我不应该费心在我的onStartCommand函数中排除空intent

我只是有点紧张尝试数字 2,以防它导致人们的设备再次惹恼他们!

以下是启用警报的方式

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

然后是这个 AlarmReceiver 类

对于_WAKEUP式警报,这将不可靠。设备很有可能在startService()调用和服务实际有机会执行某些操作之间进入睡眠状态。如果您要使用委托到服务模式,请使用WakefulBroadcastReceiver或我的WakefulIntentService进行_WAKEUP式警报。

但是在这个过程中,人们说它每天只开火一次!

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

我用这个替换了开始:

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

而且,如果这是您打算在服务中完成的所有工作,则可以完全转储该服务并将onStartCommand()胆量转移到BroadcastReceiveronReceive()中。

当工作花费太长时间以冒占用主应用程序线程的风险时(例如,>1ms)使用从接收方将工作委托给服务的模式...但是你的服务需要一个后台线程,而你的服务缺乏。由于我希望您的代码在执行时间中小于 1ms,因此您只需在onReceive()中执行此操作并简化您的应用程序,您将不再需要单独的Service,也不再需要我之前提到的任何Wakeful*东西。

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

如果每天只运行一次,最好不要有"现有服务"。您无需运行进程,占用系统 RAM,只需等待时钟滴答作响即可。

我不应该费心在我的 onStartCommand 函数中排除空意图值

如果出现以下情况,您将获得nullIntent

  • 您的进程在服务完成onStartCommand()进行startService()调用之前终止,并且

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

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

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

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

最新更新