我有以下要求。用户需要能够在我的应用中安排定期提醒,该提醒将在每天的确切时间触发推送通知。
这是我希望最终不要提交的那些问题之一,因为在编写该问题时建议使用类似的问题。但是,几个团队成员花了很多时间来查看Android Developer Docs和Stackoverflow,我们似乎离答案还很近,所以我们到了。
如果我创建提醒并将其设置为在未来5分钟内触发通知,则可以正常触发通知。
我怀疑这可能是由Android P中引入的省电,唤醒锁等更改引起的问题,因为在将目标SDK更新到28之前我们没有这个问题。这是唯一的问题,但我可以始终在运行Android P的Pixel和Pixel 3 XL上重现该问题。
例如,当用户将提醒设置为半夜的某个时间(大概是在用户处于睡眠状态,因此将有几个小时不使用电话)时,发生通知不触发的示例。这些提醒从未触发过。
我目前正在尝试使用“警报管理器”来完成此操作。
此问题似乎类似于另一个使用Alarm Manager's setRepeating方法的问题,我们发现该方法不起作用。相反,我们使用警报管理器的setExactAndAllowWhileIdle方法。我们还使用Alarm Managers setAlarmClock方法尝试了相同的实现,根据Android文档,该方法“即使系统处于低功率空闲(即打ze)模式,也将被允许触发”,但这还是没有成功
我怀疑这不起作用的原因是因为在电话处于打ze模式时,setExactAndAllowWhileIdle不会触发,类似于this question中表示的问题。此问题建议使用Firebase JobDispatcher,但由于这是内部通知,因此无论是否具有网络连接,我都需要触发该通知,这似乎消除了Firebase JobDispatcher的选择。这个问题还表明,一旦手机退出打ze模式,用户会收到通知,但我们从未收到通知,他们似乎因为缺少更好的条件而迷路了。
我已将唤醒锁定权限添加到我的AndroidManifest.xml中:
<uses-permission android:name="android.permission.WAKE_LOCK" />
这是我的接收者在AndroidManifest.xml中的注册方式
<receiver android:name="com.myapp.receiver.AlarmReceiver">
</receiver>
这是我当前的实现方式:
待处理通知的意图
Intent i = new Intent(context, ScheduleAllReceiver.class);
PendingIntent scheduleAllPendingIntent = PendingIntent.getBroadcast(context, SCHEDULER_DAILY_ALL, i, PendingIntent.FLAG_UPDATE_CURRENT);
我随后按如下方式调用方法“ createAlarm”
createAlarm(context, scheduleAllPendingIntent, calendar.getTimeInMillis());
创建警报
public static void createAlarm(Context context, PendingIntent pendingIntent, long timeinMilli) {
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
if(alarmManager != null) {
if (Build.VERSION.SDK_INT >= 23) {
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, timeinMilli, pendingIntent);
} else {
alarmManager.setExact(AlarmManager.RTC_WAKEUP, timeinMilli, pendingIntent);
}
}
}
答案 0 :(得分:4)
添加意图标志 FLAG_RECEIVER_FOREGROUND
https://developer.android.com/reference/android/content/Intent#FLAG_RECEIVER_FOREGROUND在致电广播接收器之前应该可以解决问题
Intent intent = new Intent(context, ScheduleAllReceiver.class);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
PendingIntent scheduleAllPendingIntent = PendingIntent.getBroadcast(context, SCHEDULER_DAILY_ALL, intent, PendingIntent.FLAG_UPDATE_CURRENT);
答案 1 :(得分:1)
我也遇到过类似的问题。我试过工作经理,但结果是一样的。当手机锁定并处于打ze模式时,不会触发该事件。
但是要在准确的时间触发事件,您只需要使用警报管理器。即使在打ze模式下也应该可以使用。
注册警报管理器的方法(使用设置的确切时间而不是重复)
public static void registerAlarm(Context context){
final int FIVE_MINUTES_IN_MILLI = 300000;
final int THIRTY_SECOND_IN_MILLI = 30000;
long launchTime = System.currentTimeMillis() + FIVE_MINUTES_IN_MILLI;
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, BroadcastAlarmManger.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, launchTime, pi);
else am.setExact(AlarmManager.RTC_WAKEUP, launchTime, pi);
Utility.printLog("timestamp "+launchTime);
}
广播警报接收器
公共类BroadcastAlarmManger扩展了BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
//register alarm again
registerAlarm(context);
.
.
.
.
//do your stuff
}
清单声明
<receiver
android:name="com.taxiemall.utility.BroadcastAlarmManger"
android:enabled="true"
android:exported="true"/>
此外,您还必须手动处理重新启动。每次重新启动后,已清除的已清除警报。因此,为Android重启注册一个广播接收器,然后在其中重新注册警报。
答案 2 :(得分:1)
This is the library对我有用。
答案 3 :(得分:-1)
是的,您是对的。
现在,Google建议使用WorkManager代替AlarmManager。
AlarmManager在他的工作中有很多限制。您可以找到更多信息here (doze mode)
此外,像素电话的bug带有AlarmManager
答案 4 :(得分:-1)
由于行为更改,您将无法运行长时间在Oreo中运行的后台服务,现在Oreo可以优化系统内存,电池等,这会杀死后台服务,要解决您的问题,您应该使用前台服务。
看看后台执行限制https://developer.android.com/about/versions/oreo/android-8.0-changes
我的建议是,如果您可以使用FCM,那就去做吧,因为微信之类的应用程序,Facebook都在使用它来传递通知,而他们不会遇到任何问题...
希望这有助于理解问题。...