我有以下要求。用户需要能够在我的应用中安排定期提醒,以便在每天的确切时间触发推送通知。
这是我希望最终不会提交的问题之一,因为在编写时会提出类似的问题。然而,有几个团队成员花了几个小时来浏览Android Developer Docs和Stackoverflow,我们似乎没有接近答案,所以我们就是这样。
如果我创建一个提醒并将其设置为在将来5分钟触发通知,则通知会正常启动。
我怀疑这可能是由于Android P中引入的电池节省,唤醒锁定等更改引起的问题,因为我们在将目标SDK更新到28之前没有遇到此问题。这就是说我不肯定这是唯一的问题,但我可以在运行Android P的Pixel和Pixel 3 XL上不断重现这个问题。
例如,当用户将提醒设置为在半夜的某个时间时(可能是当用户睡着并且因此将不使用电话几个小时)时,发生通知未触发的示例。这些提醒并没有被解雇。
我目前正在尝试使用Alarm Manager完成此操作。
这个问题似乎与使用Alarm Manager's setRepeating方法的另一个问题类似,我们发现这个方法不起作用。我们使用Alarm Manager的setExactAndAllowWhileIdle方法。我们还尝试了使用Alarm Managers setAlarmClock方法的相同实现,根据Android文档“即使系统处于低功耗空闲(a.k.a. doze)模式也将允许触发”,但这也是不成功的。
我怀疑这不起作用的原因是因为当手机处于打盹模式时,setExactAndAllowWhileIdle不会触发,类似于this question中表达的问题。此问题建议使用Firebase JobDispatcher但由于这是内部通知,因此我需要使用或不使用网络连接来触发通知,这似乎会消除Firebase JobDispatcher作为选项。这个问题还表明,一旦手机退出打盹模式,用户就会收到通知,但我们从未收到通知,他们似乎因缺乏更好的条款而丢失。
我已将唤醒锁权限添加到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);
}
}
}
添加意图标志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);
我遇到过类似的问题。我尝试过工作经理,但结果是一样的。当手机被锁定并处于打盹模式时,不会触发事件。
但是为了在确切时间触发事件,您只需要使用警报管理器。它甚至应该在打盹模式下工作。
注册报警管理器的方法(使用设置准确时间而不是重复)
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);
}
广播接收器用于报警
public class 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重启的广播接收器并在其中再次注册您的警报。
This is the library为我工作。
是的,你是对的。现在,Google建议使用WorkManager而不是AlarmManager。 AlarmManager在他的工作中有很多限制。你可以找到更多信息here (doze mode) 此外,像素手机有一个带alarmManager的bug
你将无法在Oreo中长时间运行后台服务,因为有行为改变,现在Oreo优化系统内存,电池等,它会杀死后台服务,解决你应该使用前台服务的问题。
看看后台执行限制https://developer.android.com/about/versions/oreo/android-8.0-changes
根据我的建议,如果你可以使用FCM然后去购买它,因为像微信,Facebook使用它的应用程序,提供通知,他们没有遇到任何问题......
希望这有助于理解问题....