You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 01:51:14