Flutter 弹窗队列管理:支持优先级的线程安全通用弹窗队列系统

在复杂的 Flutter 应用开发中,弹窗管理是一个常见难题。手动管理弹窗的显示顺序和条件判断不仅繁琐,还容易出错。为此,我们实现了一个支持优先级的线程安全通用弹窗队列管理系统。它能够自动管理弹窗的显示顺序,支持条件判断,并且可以灵活地在任何地方调用。

一、需求分析

  1. 支持弹窗队列:按顺序显示多个弹窗。
  2. 条件判断:弹窗显示前可进行条件判断。
  3. 线程安全:确保在多线程环境下操作安全。
  4. 通用性 :可在任何地方调用,不限于 StatefulWidget。
  5. 优先级支持:支持弹窗优先级,高优先级弹窗优先显示。

二、实现思路

  1. 单例模式:全局只有一个队列管理实例。
  2. 线程安全 :使用 synchronized 包确保操作安全。
  3. 优先级排序:弹窗按优先级排序,高优先级先显示。
  4. 独立函数 :提供独立的 showQueueDialog 函数,方便调用。

三、代码实现

1. 弹窗队列管理类

dart 复制代码
import 'dart:async';

import 'package:flutter/material.dart';

const _defaultTag = 'default_dialog_queue_tag';

typedef BSQueueDialogCondition = FutureOr<bool> Function(BuildContext context);
typedef BSQueueDialogShow = FutureOr<void> Function(BuildContext context);

class BSQueueDialog {
  /// 是否应该显示弹窗
  final BSQueueDialogCondition? shouldShow;

  /// 显示弹窗
  final BSQueueDialogShow show;

  /// 弹窗优先级
  final int priority;

  const BSQueueDialog({
    this.shouldShow,
    required this.show,
    // 默认优先级为0,数值越大优先级越高
    this.priority = 0,
  });
}

class DialogQueueManager {
  static final _instance = DialogQueueManager._internal();

  factory DialogQueueManager() => _instance;

  DialogQueueManager._internal();

  final _dialogQueue = <String, List<BSQueueDialog>>{};
  final _displayingDialog = <String, BSQueueDialog>{};

  Future<void> showQueueDialog<R>({
    required BuildContext context,
    BSQueueDialogCondition? shouldShow,
    required BSQueueDialogShow show,
    String tag = _defaultTag,
    int priority = 0,
  }) async {
    final dialog =
        BSQueueDialog(shouldShow: shouldShow, show: show, priority: priority);
    var queue = _dialogQueue[tag];
    if (queue == null) {
      queue = <BSQueueDialog>[];
      _dialogQueue[tag] = queue;
    }
    queue.add(dialog);
    // 按优先级排序队列
    queue.sort((a, b) => b.priority.compareTo(a.priority));

    // 检查是否有正在显示的弹窗
    final displayingDialog = _displayingDialog[tag];
    if (displayingDialog == null) {
      _displayingDialog[tag] = dialog;
      await _showQueueDialog(context, tag);
    } else if (dialog.priority > displayingDialog.priority) {
      // 如果新弹窗优先级高,则关闭当前弹窗并显示新弹窗
      Navigator.of(context).pop(); 
      _displayingDialog.remove(tag);
      // 将当前弹窗重新添加到队列中
      queue.add(displayingDialog);
      await _showQueueDialog(context, tag); // 显示高优先级弹窗
    }
  }

  Future<void> _showQueueDialog<R>(BuildContext context, String tag) async {
    final queue = _dialogQueue[tag];
    if (queue == null || queue.isEmpty) {
      _dialogQueue.remove(tag);
      return;
    }
    final dialog = queue.removeAt(0);
    final shouldShow = await dialog.shouldShow?.call(context) ?? false;
    if (shouldShow) {
      _displayingDialog[tag] = dialog;
      await dialog.show(context);
      _displayingDialog.remove(tag);
    }
    return _showQueueDialog(context, tag);
  }
}

2. 独立的 showQueueDialog 函数

dart 复制代码
Future<void> showQueueDialog<R>({
  required BuildContext context,
  BSQueueDialogCondition? shouldShow,
  required BSQueueDialogShow show,
  String tag = _defaultTag,
  int priority = 0, // 弹窗优先级
}) async {
  return DialogQueueManager().showQueueDialog(
    context: context,
    shouldShow: shouldShow,
    show: show,
    tag: tag,
    priority: priority,
  );
}

3. 使用示例

dart 复制代码
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Queue Dialog Example',
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Queue Dialog Example'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            showQueueDialog(
              context: context,
              shouldShow: (context) async {
                // 可以在这里添加条件逻辑
                return true;
              },
              show: (context) async {
                await showDialog(
                  context: context,
                  builder: (context) => AlertDialog(
                    title: Text('Queue Dialog'),
                    content: Text('This is a queued dialog with priority.'),
                    actions: [
                      TextButton(
                        onPressed: () => Navigator.pop(context),
                        child: Text('Close'),
                      ),
                    ],
                  ),
                );
              },
              priority: 1, // 设置弹窗优先级
            );
          },
          child: Text('Show Queue Dialog'),
        ),
      ),
    );
  }
}

四、代码说明

  1. 单例模式 :通过 DialogQueueManager 类实现单例模式,确保全局只有一个队列管理实例。
  2. 线程安全 :使用 synchronized 包中的 _lock 对象,确保对队列的操作是线程安全的。
  3. 优先级排序:弹窗按优先级排序,高优先级的弹窗会优先显示。
  4. 独立函数 :提供独立的 showQueueDialog 函数,可在任何地方调用,不限于 StatefulWidget。

五、总结

通过上述实现,我们构建了一个支持优先级的线程安全通用弹窗队列管理系统。它不仅支持弹窗的按序显示和条件判断,还支持弹窗优先级,高优先级的弹窗会优先显示。这种方式更加灵活,适用于更多场景,能够有效简化弹窗的管理逻辑,提高代码的可维护性。

相关推荐
IT大白鼠3 分钟前
2026年9月至今重大安全漏洞专题报告——国产软件与终端高危漏洞深度解析
安全·漏洞·搜狗
u0111026754 分钟前
WebP 转成 PNG 后为什么更大?图片格式转换不等于压缩
前端·javascript·vue.js
Safeploy安策数据13 分钟前
如何挑选专业的密钥管理体系?从制度、流程、工具三层评估
安全·云计算
Mikko732 分钟前
Spring Boot 3.5.16 自带的 Tomcat 10.1.55 中了哪些 CVE?其中一条是修上一个漏洞时带进来的
java·spring boot·后端·安全·tomcat
pt104334 分钟前
Cisco设备网络安全系列-4:分层网络安全基础设施案例与核心技术
网络·安全
小皮虾38 分钟前
小程序全局状态还能这么简单?只需初始化一次,页面自动同步
前端·javascript·微信小程序
骇客野人1 小时前
Windows 安全清理临时文件 bat 脚本
windows·安全
一心同学1 小时前
Hermes架构拆解之Tool执行安全机制
安全·架构·agent·hermes
FungLeo1 小时前
成为全栈·Flutter App 篇·Markdown 编辑器:编辑、预览与离开保护
flutter·移动开发·markdown编辑器·表单设计·成为全栈·草稿保存
daols881 小时前
vue 甘特图组件 vxe-gantt 修改滚动条样式-让滚动条自动隐藏
javascript·vue.js·甘特图