Flutter Local Notification重复显示相同随机字符串问题求助
问题分析
你当前使用periodicallyShow方法时,是将**提前生成好的randomName**作为通知内容传入的——这个方法会一次性固定通知内容,后续重复推送的都是第一次传入的字符串,不会每次触发时重新执行随机逻辑,这就是为什么内容始终重复的原因。
解决方案
放弃periodicallyShow,改用单次通知+定时调度的方式,每次推送前生成新的不重复随机内容,并安排下一次通知。同时通过集合记录已推送内容,避免重复。
步骤1:添加依赖
需要引入时区处理依赖,用于精准调度每日通知:
dependencies: flutter_local_notifications: ^latest_version timezone: ^latest_version
步骤2:初始化时区
在main函数中初始化时区支持:
import 'package:timezone/timezone.dart' as tz; import 'package:timezone/data/latest.dart' as tz; void main() async { tz.initializeTimeZones(); runApp(const MyApp()); }
步骤3:重构通知服务类
import 'dart:math'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:timezone/timezone.dart' as tz; class NotificationService { final FlutterLocalNotificationsPlugin _notificationsPlugin = FlutterLocalNotificationsPlugin(); final Set<String> _usedNames = {}; // 替换成你的字符串列表 final List<String> _names = ["内容1", "内容2", "内容3", "内容4", "内容5"]; // 初始化通知配置 Future<void> init() async { const AndroidInitializationSettings androidSettings = AndroidInitializationSettings('@mipmap/ic_launcher'); const DarwinInitializationSettings iosSettings = DarwinInitializationSettings(); const InitializationSettings initSettings = InitializationSettings(android: androidSettings, iOS: iosSettings); await _notificationsPlugin.initialize(initSettings); } // 生成不重复的随机字符串 String _getUniqueRandomName() { // 所有内容推完后重置记录 if (_usedNames.length == _names.length) { _usedNames.clear(); } String? selectedName; final random = Random(); // 循环直到找到未推送过的内容 do { selectedName = _names[random.nextInt(_names.length)]; } while (_usedNames.contains(selectedName)); _usedNames.add(selectedName!); return selectedName; } // 调度每日通知(含当前推送+次日调度) Future<void> scheduleDailyNotification(String title) async { // 生成当前要推送的内容 final currentContent = _getUniqueRandomName(); // 推送当前通知 await _notificationsPlugin.show( 1, title, currentContent, const NotificationDetails( android: AndroidNotificationDetails( 'main_channel', 'Main Channel', channelDescription: "日常通知", importance: Importance.max, priority: Priority.max, ), iOS: DarwinNotificationDetails( sound: 'default.wav', presentAlert: true, presentBadge: true, presentSound: true, ), ), androidAllowWhileIdle: true, ); // 计算次日同一时间的推送点(这里设置为每天10点) var nextTime = tz.TZDateTime.now(tz.local).add(const Duration(days: 1)); nextTime = tz.TZDateTime( tz.local, nextTime.year, nextTime.month, nextTime.day, 10, 0, ); // 如果次日时间已过(比如当前是11点,设置的是10点),则延后到第三天 if (nextTime.isBefore(tz.TZDateTime.now(tz.local))) { nextTime = nextTime.add(const Duration(days: 1)); } // 调度下一次通知 await _notificationsPlugin.zonedSchedule( 1, title, _getUniqueRandomName(), nextTime, const NotificationDetails( android: AndroidNotificationDetails( 'main_channel', 'Main Channel', channelDescription: "日常通知", importance: Importance.max, priority: Priority.max, ), iOS: DarwinNotificationDetails( sound: 'default.wav', presentAlert: true, presentBadge: true, presentSound: true, ), ), androidAllowWhileIdle: true, uiLocalNotificationDateInterpretation: UILocalNotificationDateInterpretation.absoluteTime, matchDateTimeComponents: DateTimeComponents.time, ); } }
步骤4:按钮点击调用
onPressed: () async { setState(() { showToast(); }); final notificationService = NotificationService(); await notificationService.init(); await notificationService.scheduleDailyNotification('$randomNames${widget.userPost}'); },
关键说明
- 抛弃
periodicallyShow:该方法是静态重复通知,内容无法动态更新,不适合需要随机内容的场景。 - 去重逻辑:通过
Set记录已推送内容,确保每次推送的字符串唯一,所有内容推完后自动重置。 - 时区调度:使用
zonedSchedule保证每日固定时间推送,避免因时区或日期变化导致的调度错误。
内容的提问来源于stack exchange,提问作者Marian
相关产品推荐
相关产品推荐

