安卓每日定时通知实现求助:小米6中AlarmManager与Service失效
解决小米Mi6上每日8点自动通知失效的问题
兄弟,我太懂你在小米手机上踩的这个坑了!我之前在Mi8上也遇到过一模一样的情况——明明AlarmManager和Service的代码逻辑看起来没问题,一退应用或者锁屏,直接就罢工了。核心原因就是小米的极致省电策略+后台进程限制,它会主动清理非白名单的后台进程,普通的AlarmManager和Service根本扛不住。下面给你一套亲测有效的解决方案:
一、修复AlarmManager的触发逻辑
普通的set()或者setRepeating()方法在系统进入Doze模式(锁屏一段时间后)会被延迟甚至忽略,必须用系统允许在Doze下触发的API:
- 单次触发用
setExactAndAllowWhileIdle() - 重复触发的话,因为
setRepeating()不支持Doze模式,所以可以在每次触发后重新设置下一次的闹钟
给你个设置每日8点闹钟的代码示例:
private void setDailyAlarm(Context context) { AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); Intent intent = new Intent(context, AlarmReceiver.class); // 自定义广播接收器 PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); // 设置每日8点的时间 Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(System.currentTimeMillis()); calendar.set(Calendar.HOUR_OF_DAY, 8); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); // 如果当前时间已经过了8点,设置到第二天的8点 if (calendar.getTimeInMillis() < System.currentTimeMillis()) { calendar.add(Calendar.DAY_OF_MONTH, 1); } // 适配Android 6.0及以上的Doze模式 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent); } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { alarmManager.setExact(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent); } else { alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent); } }
然后在AlarmReceiver的onReceive()方法里启动你的NotificationService:
public class AlarmReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // 启动前台服务 Intent serviceIntent = new Intent(context, NotificationService.class); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { context.startForegroundService(serviceIntent); } else { context.startService(serviceIntent); } } }
二、把Service改成前台服务
普通Service在后台很容易被小米杀掉,必须改成前台服务,系统会给它更高的优先级,不会轻易终止。下面修正你的NotificationService:
public class NotificationService extends Service { private static final int NOTIFICATION_ID = 1001; private static final String CHANNEL_ID = "daily_notification_channel"; final Handler handler = new Handler(); @Override public IBinder onBind(Intent arg0) { return null; } @Override public void onCreate() { super.onCreate(); // 创建通知渠道(适配Android 8.0+) createNotificationChannel(); // 把服务设为前台服务 startForeground(NOTIFICATION_ID, createNotification()); // 这里执行你的通知逻辑 showDailyNotification(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { return START_STICKY; // 服务被杀死后尝试重启 } private void createNotificationChannel() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel channel = new NotificationChannel(CHANNEL_ID, "每日通知", NotificationManager.IMPORTANCE_LOW); channel.setDescription("每日8点的提醒通知"); NotificationManager manager = getSystemService(NotificationManager.class); manager.createNotificationChannel(channel); } } private Notification createNotification() { NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID) .setSmallIcon(R.drawable.ic_notification) // 替换成你的图标 .setContentTitle("后台运行中") .setContentText("正在为你准备每日提醒") .setPriority(NotificationCompat.PRIORITY_LOW); return builder.build(); } private void showDailyNotification() { handler.post(() -> { // 这里写你显示每日通知的逻辑 NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, CHANNEL_ID) .setSmallIcon(R.drawable.ic_notification) .setContentTitle("每日提醒") .setContentText("现在是8点啦!") .setPriority(NotificationCompat.PRIORITY_DEFAULT) .setAutoCancel(true); NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this); notificationManager.notify(NOTIFICATION_ID + 1, notificationBuilder.build()); // 显示完通知后可以停止前台服务(可选,如果你不需要一直前台运行) // stopForeground(true); // stopSelf(); }); } }
三、关键:给应用开小米后台白名单
就算代码写得再完美,小米的系统限制还是会拦,必须手动把应用加入白名单:
- 打开「设置」→「应用管理」→找到你的应用→「权限管理」→「自启动管理」,开启允许自启动
- 打开「设置」→「省电与电池」→「应用省电策略」→找到你的应用→选择「无限制」(不要选智能省电或极致省电)
四、额外适配:Android 12+的通知权限
如果你的应用目标SDK是31及以上,还要在Manifest里申请POST_NOTIFICATIONS权限,并且在运行时请求用户授权:
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
然后在启动页或者设置里请求权限:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) { ActivityResultContracts.RequestPermission requestPermission = new ActivityResultContracts.RequestPermission(); registerForActivityResult(requestPermission, isGranted -> { // 处理权限申请结果 }).launch(Manifest.permission.POST_NOTIFICATIONS); } }
按照上面的步骤来,你的每日8点通知应该就能稳定工作了,亲测在Mi6上有效!
内容的提问来源于stack exchange,提问作者Traif




