Android Java实现每日定时通知失败,onTimeSet触发报InputDispatcher错误
问题根因
- 你遇到的
Window ... has no registered input channel报错是时序问题导致:onTimeSet()是TimePickerDialog的回调,触发时Dialog还未完成销毁流程,此时你直接执行Activity跳转,SetNotificationActivity被切到后台后,Dialog的输入管道还没来得及注销就被系统回收,触发报错。 - 无法收到通知是多版本适配问题导致:PendingIntent合法性、AlarmManager权限与接口适配、通知权限/通道配置不正确都会导致广播不触发、通知无法展示。
修复步骤
1. 修复时序报错
调整跳转逻辑,等待TimePickerDialog完全销毁后再执行页面跳转,修改SetNotificationActivity的对应代码:
@Override public void onTimeSet(TimePicker view, int hourOfDay, int minute) { Calendar c = Calendar.getInstance(); c.set(Calendar.HOUR_OF_DAY, hourOfDay); c.set(Calendar.MINUTE, minute); c.set(Calendar.SECOND, 0); // 新增:对齐整分钟,避免秒级误差 startAlarm(c); // 新增:延迟300ms跳转,等待Dialog销毁完成 new Handler(Looper.getMainLooper()).postDelayed(() -> { startActivity(new Intent(SetNotificationActivity.this, HomeActivity.class)); finish(); }, 300); } private void startAlarm(Calendar c) { AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE); Intent intent = new Intent(this, AlertReceiver.class); // 修复:安卓12及以上要求PendingIntent必须指定可变性标识 int pendingFlag = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? PendingIntent.FLAG_IMMUTABLE : 0; PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 1, intent, pendingFlag); if (c.before(Calendar.getInstance())) c.add(Calendar.DATE, 1); // 修复:高版本安卓用精确闹钟接口,避免低电耗模式拦截 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, c.getTimeInMillis(), pendingIntent); } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { alarmManager.setExact(AlarmManager.RTC_WAKEUP, c.getTimeInMillis(), pendingIntent); } else { alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, c.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pendingIntent); } // 移除原有跳转逻辑,移到onTimeSet的延迟任务中 }
同时调整跳过按钮的跳转顺序,避免类似时序问题:
skip_btn.setOnClickListener(v -> { startActivity(new Intent(SetNotificationActivity.this, HomeActivity.class)); finish(); });
2. 修复广播内PendingIntent适配
修改AlertReceiver中的PendingIntent配置,适配高版本安卓要求:
@Override public void onReceive(Context context, Intent intent) { Intent intent1 = new Intent(context, SplashScreenActivity.class); intent1.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); // 修复:适配高版本PendingIntent标识要求 int pendingFlag = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? PendingIntent.FLAG_IMMUTABLE : PendingIntent.FLAG_UPDATE_CURRENT; PendingIntent pendingIntent = PendingIntent.getActivity(context, 100, intent1, pendingFlag); NotificationHelper notificationHelper = new NotificationHelper(context); NotificationCompat.Builder nb = notificationHelper.getChannelNotification(); nb.setContentIntent(pendingIntent); // 恢复点击跳转逻辑,可选 notificationHelper.getManager().notify(1, nb.build()); // 新增:如果需要每日重复提醒,每次收到广播后重新设置下一天的闹钟 Calendar nextAlarm = Calendar.getInstance(); nextAlarm.add(Calendar.DATE, 1); // 此处复用SetNotificationActivity中的闹钟设置逻辑即可 }
3. 补充权限与配置
在AndroidManifest.xml中添加必要权限:
<!-- 开机自启权限,重启设备后闹钟不会丢失 --> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <!-- 通知振动权限 --> <uses-permission android:name="android.permission.VIBRATE" /> <!-- 安卓13+ 通知推送权限,需要动态申请 --> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <!-- 安卓12+ 精确闹钟权限 --> <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" /> <!-- 确保AlertReceiver已在清单文件中注册 --> <receiver android:name=".AlertReceiver" />
4. 确认通知通道配置
安卓8.0及以上系统必须创建合法的通知通道才能推送通知,确保你的NotificationHelper中包含类似通道创建逻辑:
public class NotificationHelper extends ContextWrapper { public static final String CHANNEL_ID = "daily_notify_channel"; private NotificationManager manager; public NotificationHelper(Context base) { super(base); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel channel = new NotificationChannel( CHANNEL_ID, "每日提醒", NotificationManager.IMPORTANCE_HIGH ); channel.enableLights(true); channel.enableVibration(true); getManager().createNotificationChannel(channel); } } public NotificationCompat.Builder getChannelNotification() { return new NotificationCompat.Builder(getApplicationContext(), CHANNEL_ID) .setSmallIcon(R.drawable.ic_notification) // 替换为你的通知图标 .setContentTitle("每日提醒") .setContentText("你设置的提醒时间到了") .setPriority(NotificationCompat.PRIORITY_HIGH) .setAutoCancel(true); } public NotificationManager getManager() { if (manager == null) { manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); } return manager; } }
内容的提问来源于stack exchange,提问作者George Sepetadelis
相关产品推荐
相关产品推荐

