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

五、总结

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

相关推荐
极创信息21 分钟前
Linux挖矿病毒深度清理实战教程,从进程隐藏、Rootkit驻留到彻底根除
java·大数据·linux·运维·安全·tomcat·健康医疗
数据知道29 分钟前
指纹浏览器本地存储“孤岛化”:IndexedDB、LocalStorage、SessionStorage 的安全隔离
爬虫·安全·数据采集·指纹浏览器
xhtdj1 小时前
智源大会圆桌大模型没有终局具身智能可能是中国的 AlphaGo 时刻
人工智能·clickhouse·安全·动态规划
HavenlonLabs1 小时前
区块链解决信任分布,AI 需要解决能力控制
人工智能·安全·区块链
MartinYeung51 小时前
[论文学习]大型语言模型(LLM)安全与隐私-基于善、恶、丑的深度分析
学习·安全·语言模型
丷丩1 小时前
MapLibre GL JS第47课:添加动画图标
javascript·gis·动画·mapbox·maplibre
独泪了无痕1 小时前
Vue3中防御XSS攻击的“特效药”-DOMPurify
前端·vue.js·安全
快乐的哈士奇2 小时前
【Next.js实战①】Gmail API 按柜号检索邮件:OAuth 双 Cookie 与搜索 Fallback
开发语言·javascript·ecmascript
云水一下2 小时前
Vue.js从零到精通系列(五):全局状态管理——Pinia 核心与实践
前端·javascript·vue.js
ylscode2 小时前
GreatXML BitLocker绕过漏洞深度解析:Windows Defender离线扫描如何被改造成本地提权后门
windows·安全