Android Studio中每日定时通知调度功能失效问题求助
我看了你贴的代码,这里有几个关键问题导致通知功能无法正常运行,咱们一步步来修复:
1. PendingIntent的Flag兼容问题(Android 12+)
你创建PendingIntent时用的是0,在Android 12(API 31)及以上版本,必须指定FLAG_IMMUTABLE或FLAG_MUTABLE,否则会抛出异常。建议用FLAG_IMMUTABLE(因为你的广播不需要修改Intent内容):
修改MainActivity和MyService里的PendingIntent创建代码:
pendingIntent = PendingIntent.getBroadcast(this, 0, myIntent, PendingIntent.FLAG_IMMUTABLE);
如果你的targetSdkVersion低于31,也可以加上FLAG_UPDATE_CURRENT确保Intent更新:
pendingIntent = PendingIntent.getBroadcast(this, 0, myIntent, PendingIntent.FLAG_UPDATE_CURRENT | (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S ? PendingIntent.FLAG_IMMUTABLE : 0));
2. Intent Action设置顺序错误
在MainActivity的startAlarm方法里,你先创建PendingIntent再给Intent设置Action,这会导致PendingIntent里的Intent没有携带Action,Receiver里的intent.getAction().equals("MY_NOTIFICATION_MESSAGE")判断永远不成立,通知不会触发。要先设置Action,再创建PendingIntent:
myIntent = new Intent(MainActivity.this,AlarmNotificationReceiver.class); myIntent.setAction("MY_NOTIFICATION_MESSAGE"); // 先设置Action pendingIntent = PendingIntent.getBroadcast(this,0,myIntent,PendingIntent.FLAG_IMMUTABLE);
MyService里的startAlarm方法也要做同样的修改。
3. API 26+必须创建NotificationChannel
从Android 8.0(API 26)开始,所有通知都必须属于一个NotificationChannel,否则通知不会显示。在AlarmNotificationReceiver的onReceive方法开头添加:
// 创建NotificationChannel(API 26+) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { String channelId = "daily_alarm_channel"; String channelName = "每日通知"; NotificationChannel channel = new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_DEFAULT); channel.enableVibration(true); NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); notificationManager.createNotificationChannel(channel); // 给Builder设置ChannelId builder.setChannelId(channelId); }
4. BootReceiver启动服务的兼容性问题(Android 8+)
Android 8.0之后后台启动服务会被限制,不能直接用context.startService(i),需要用startForegroundService,同时MyService必须在启动后5秒内调用startForeground显示前台通知:
首先在AndroidManifest.xml里添加前台服务权限:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
修改BootReceiver的onReceive方法:
public void onReceive(Context context, Intent intent) { if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) { Intent i = new Intent(context, MyService.class); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { context.startForegroundService(i); } else { context.startService(i); } Toast.makeText(context, "Booting Completed", Toast.LENGTH_LONG).show(); } }
然后修改MyService的onCreate方法,添加前台通知:
@Override public void onCreate() { super.onCreate(); // 创建前台通知(API 26+需要Channel) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { String channelId = "service_channel"; NotificationChannel channel = new NotificationChannel(channelId, "后台服务", NotificationManager.IMPORTANCE_LOW); NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); manager.createNotificationChannel(channel); Notification notification = new Notification.Builder(this, channelId) .setContentTitle("服务运行中") .setContentText("正在维护定时通知") .setSmallIcon(R.mipmap.ic_launcher) .build(); startForeground(1, notification); } startAlarm(true,true); }
5. 避免PendingIntent冲突
MainActivity和MyService里创建的PendingIntent用的是同一个requestCode(0),可能会互相覆盖。建议给它们设置不同的requestCode,比如MainActivity用1,MyService用2:
MainActivity里:
pendingIntent = PendingIntent.getBroadcast(this, 1, myIntent, PendingIntent.FLAG_IMMUTABLE);
MyService里:
pendingIntent = PendingIntent.getBroadcast(this, 2, myIntent, PendingIntent.FLAG_IMMUTABLE);
6. 处理当前时间已过设置时间的情况
如果当前时间已经超过了你设置的17:12或18:45,setRepeating会在第二天的同一时间才触发通知。如果你希望如果当前时间已过,就立即触发一次,可以添加判断:
Calendar calendar= Calendar.getInstance(); calendar.set(Calendar.HOUR_OF_DAY,17); calendar.set(Calendar.MINUTE, 12); calendar.set(Calendar.SECOND, 0); // 加上秒数更精确 // 如果当前时间已过设置时间,加一天 if (calendar.getTimeInMillis() < System.currentTimeMillis()) { calendar.add(Calendar.DAY_OF_YEAR, 1); }
最后检查配置
- 去掉MyService里无效的
android:permission="TODO"配置 - 确保测试时先手动点击按钮触发一次,验证通知是否弹出,再测试开机自启和每日重复功能
把这些修改都做完之后,你的定时通知应该就能正常工作了。
内容的提问来源于stack exchange,提问作者GinnyWeasley

