如何在Flutter中实现通用应用消息队列及关闭时的UI确认机制
Flutter通用应用消息队列实现方案
核心设计要点
- 全局单例的单向消息管道,支持任意代码模块投递消息
- 消息携带可执行回调,由UI层消费者(如AlertDialog)触发执行
- 队列关闭时自动检测活跃消息,弹出确认框询问是否取消所有未处理项
1. 定义消息模型
封装消息实体,包含唯一标识、执行回调、状态标记:
class AppMessage { final String id; final VoidCallback callback; bool isCancelled; AppMessage({ required this.id, required this.callback, this.isCancelled = false, }); }
2. 实现全局消息队列核心类
采用单例模式确保全局唯一实例,内置队列管理、状态控制和关闭确认逻辑:
import 'package:flutter/material.dart'; class AppMessageQueue { static final AppMessageQueue _instance = AppMessageQueue._internal(); factory AppMessageQueue() => _instance; AppMessageQueue._internal(); final List<AppMessage> _messageQueue = []; bool _isClosed = false; final ValueNotifier<List<AppMessage>> _queueNotifier = ValueNotifier([]); // 对外暴露队列变化监听 ValueNotifier<List<AppMessage>> get queueNotifier => _queueNotifier; // 投递消息到队列 void enqueueMessage(AppMessage message) { if (_isClosed) return; _messageQueue.add(message); _queueNotifier.value = List.from(_messageQueue); } // 标记消息为已取消 void markMessageAsCancelled(String messageId) { final message = _messageQueue.firstWhere((m) => m.id == messageId); message.isCancelled = true; _queueNotifier.value = List.from(_messageQueue); } // 关闭队列并触发确认逻辑 Future<void> closeQueue(BuildContext context) async { if (_isClosed) return; // 筛选未取消的活跃消息 final activeMessages = _messageQueue.where((m) => !m.isCancelled).toList(); if (activeMessages.isNotEmpty) { final shouldCancel = await showDialog<bool>( context: context, builder: (ctx) => AlertDialog( title: const Text('确认关闭'), content: const Text('队列中还有未处理的消息,是否标记所有消息为已取消?'), actions: [ TextButton( onPressed: () => Navigator.pop(ctx, false), child: const Text('取消'), ), TextButton( onPressed: () => Navigator.pop(ctx, true), child: const Text('确认'), ), ], ), ); if (shouldCancel != true) { // 用户取消关闭操作,终止流程 return; } // 批量标记所有活跃消息为已取消 for (final msg in activeMessages) { msg.isCancelled = true; } _queueNotifier.value = List.from(_messageQueue); } _isClosed = true; _queueNotifier.value = List.from(_messageQueue); } }
3. UI层消费者实现
在全局组件中监听队列变化,处理消息回调(以弹出AlertDialog为例):
class MessageConsumerPage extends StatefulWidget { const MessageConsumerPage({super.key}); @override State<MessageConsumerPage> createState() => _MessageConsumerPageState(); } class _MessageConsumerPageState extends State<MessageConsumerPage> { late final AppMessageQueue _queue; @override void initState() { super.initState(); _queue = AppMessageQueue(); _queue.queueNotifier.addListener(_processPendingMessages); } void _processPendingMessages() { // 过滤出未取消的消息,逐个触发回调 final pendingMessages = _queue.queueNotifier.value .where((m) => !m.isCancelled) .toList(); for (final msg in pendingMessages) { showDialog( context: context, builder: (ctx) => AlertDialog( title: const Text('消息通知'), content: const Text('即将执行消息回调'), actions: [ TextButton( onPressed: () { msg.callback(); _queue.markMessageAsCancelled(msg.id); Navigator.pop(ctx); }, child: const Text('确定'), ), ], ), ); } } @override void dispose() { _queue.queueNotifier.removeListener(_processPendingMessages); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('消息队列演示')), body: Center( child: ElevatedButton( onPressed: () { // 模拟定时器触发队列关闭 Future.delayed(const Duration(seconds: 2), () { _queue.closeQueue(context); }); }, child: const Text('触发队列关闭'), ), ), ); } }
4. 其他模块投递消息示例
任意业务模块都可直接调用队列方法投递消息:
// 业务模块中发送测试消息 void sendBusinessMessage() { final message = AppMessage( id: DateTime.now().millisecondsSinceEpoch.toString(), callback: () { print('执行业务回调:处理订单支付逻辑'); }, ); AppMessageQueue().enqueueMessage(message); }
内容的提问来源于stack exchange,提问作者Richard Haven
相关产品推荐
相关产品推荐

