Flutter之全局路由事件监听器RouteListenerManager

RouteListenerManager 路由监听管理器

概述

RouteListenerManager 是一个用于管理Flutter应用路由监听器的单例类,它提供了统一的路由事件监听和通知机制。该管理器配合 GlobalRouteObserver 类,能够全局监听应用的路由变化,包括路由跳转、返回、替换和移除等操作。

核心特性

  • 单例模式:确保全局只有一个路由监听管理器实例

  • 多种路由事件监听:支持路由跳转、返回、替换、移除四种事件类型

  • 异常处理:监听器执行过程中的异常不会影响其他监听器

  • 全局路由观察 :通过 GlobalRouteObserver 自动捕获所有路由变化

  • 灵活管理:支持动态添加、移除监听器

类结构

RouteListenerManager

单例实现
dart 复制代码
static final RouteListenerManager _instance = RouteListenerManager._internal();

factory RouteListenerManager() => _instance;

static RouteListenerManager get instance => _instance;

RouteListenerManager._internal();
监听器存储
  • _pushListeners: 路由跳转监听器列表

  • _popListeners: 路由返回监听器列表

  • _replaceListeners: 路由替换监听器列表

  • _removeListeners: 路由移除监听器列表

API 文档

监听器管理方法

添加监听器
addPushListener
dart 复制代码
void addPushListener(Function(String route) listener)
  • 功能:添加路由跳转监听器

  • 参数listener - 接收路由名称的回调函数

  • 用途:当发生路由跳转时触发

addPopListener
dart 复制代码
void addPopListener(Function(String route) listener)
  • 功能:添加路由返回监听器

  • 参数listener - 接收路由名称的回调函数

  • 用途:当发生路由返回时触发

addReplaceListener
dart 复制代码
void addReplaceListener(Function(String newRoute, String oldRoute) listener)
  • 功能:添加路由替换监听器

  • 参数listener - 接收新路由名称和旧路由名称的回调函数

  • 用途:当发生路由替换时触发

addRemoveListener
dart 复制代码
void addRemoveListener(Function(String route) listener)
  • 功能:添加路由移除监听器

  • 参数listener - 接收路由名称的回调函数

  • 用途:当发生路由移除时触发

移除监听器
removePushListener
dart 复制代码
void removePushListener(Function(String route) listener)
  • 功能:移除指定的路由跳转监听器
removePopListener
dart 复制代码
void removePopListener(Function(String route) listener)
  • 功能:移除指定的路由返回监听器
removeReplaceListener
dart 复制代码
void removeReplaceListener(Function(String newRoute, String oldRoute) listener)
  • 功能:移除指定的路由替换监听器
removeRemoveListener
dart 复制代码
void removeRemoveListener(Function(String route) listener)
  • 功能:移除指定的路由移除监听器
removeAllListener
dart 复制代码
void removeAllListener()
  • 功能:移除所有类型的监听器

  • 用途:清理所有监听器,通常在应用退出时调用

通知方法
notifyPush
dart 复制代码
void notifyPush(String route)
  • 功能:通知所有路由跳转监听器

  • 异常处理:单个监听器异常不会影响其他监听器执行

notifyPop
dart 复制代码
void notifyPop(String route)
  • 功能:通知所有路由返回监听器

  • 异常处理:单个监听器异常不会影响其他监听器执行

notifyReplace
dart 复制代码
void notifyReplace(String newRoute, String oldRoute)
  • 功能:通知所有路由替换监听器

  • 异常处理:单个监听器异常不会影响其他监听器执行

notifyRemove
dart 复制代码
void notifyRemove(String route)
  • 功能:通知所有路由移除监听器

  • 异常处理:单个监听器异常不会影响其他监听器执行

GlobalRouteObserver

类定义
dart 复制代码
class GlobalRouteObserver extends NavigatorObserver
重写方法
didPush
dart 复制代码
void didPush(Route<dynamic> route, Route<dynamic>? previousRoute)
  • 功能:监听路由跳转事件

  • 实现 :提取路由名称并调用 RouteListenerManager().notifyPush()

  • 日志:输出路由跳转信息

didPop
dart 复制代码
void didPop(Route<dynamic> route, Route<dynamic>? previousRoute)
  • 功能:监听路由返回事件

  • 实现 :提取路由名称并调用 RouteListenerManager().notifyPop()

  • 日志:输出路由返回信息

didReplace
dart 复制代码
void didReplace({Route<dynamic>? newRoute, Route<dynamic>? oldRoute})
  • 功能:监听路由替换事件

  • 实现 :提取新旧路由名称并调用 RouteListenerManager().notifyReplace()

  • 日志:输出路由替换信息

  • 安全检查:确保新旧路由都不为空

didRemove
dart 复制代码
void didRemove(Route<dynamic> route, Route<dynamic>? previousRoute)
  • 功能:监听路由移除事件

  • 实现 :提取路由名称并调用 RouteListenerManager().notifyRemove()

  • 日志:输出路由移除信息

使用示例

1. 基本使用

dart 复制代码
// 获取管理器实例

final routeManager = RouteListenerManager.instance;

  


// 添加路由跳转监听器

routeManager.addPushListener((String route) {

  print('路由跳转到: $route');

  // 执行自定义逻辑,如埋点统计、页面预加载等

});

  


// 添加路由返回监听器

routeManager.addPopListener((String route) {

  print('从路由返回: $route');

  // 执行自定义逻辑,如清理资源、保存状态等

});

  


// 添加路由替换监听器

routeManager.addReplaceListener((String newRoute, String oldRoute) {

  print('路由替换: $oldRoute -> $newRoute');

  // 执行自定义逻辑

});

2. 在MaterialApp中注册全局观察者

dart 复制代码
class MyApp extends StatelessWidget {

  @override

  Widget build(BuildContext context) {

    return MaterialApp(

      navigatorObservers: [

        GlobalRouteObserver(), // 注册全局路由观察者

      ],

      // 其他配置...

    );

  }

}

3. 动态管理监听器

dart 复制代码
class MyPage extends StatefulWidget {

  @override

  _MyPageState createState() => _MyPageState();

}

  


class _MyPageState extends State<MyPage> {

  late Function(String) routeListener;

  


  @override

  void initState() {

    super.initState();

    

    // 创建监听器

    routeListener = (String route) {

      print('页面 $route 被访问');

    };

    

    // 添加监听器

    RouteListenerManager.instance.addPushListener(routeListener);

  }

  


  @override

  void dispose() {

    // 移除监听器,避免内存泄漏

    RouteListenerManager.instance.removePushListener(routeListener);

    super.dispose();

  }

}

4. 清理所有监听器

dart 复制代码
// 在应用退出时清理所有监听器

void cleanup() {

  RouteListenerManager.instance.removeAllListener();

}

设计模式

单例模式

  • 确保全局只有一个 RouteListenerManager 实例

  • 通过私有构造函数和静态实例实现

  • 提供工厂构造函数和静态getter两种访问方式

观察者模式

  • RouteListenerManager 作为主题(Subject)

  • 各种监听器作为观察者(Observer)

  • 当路由事件发生时,自动通知所有注册的观察者

策略模式

  • 不同类型的路由事件使用不同的处理策略

  • 通过函数回调实现灵活的事件处理逻辑

异常处理

所有通知方法都包含异常处理机制:

dart 复制代码
void notifyPush(String route) {

  for (final listener in _pushListeners) {

    try {

      listener(route);

    } catch (e) {

      debugPrint('Route push listener error: $e');

    }

  }

}
  • 单个监听器的异常不会影响其他监听器的执行

  • 异常信息会通过 debugPrint 输出到控制台

  • 确保系统的稳定性和可靠性

注意事项

  1. 内存管理:及时移除不再需要的监听器,避免内存泄漏

  2. 异常处理:监听器函数应该处理可能的异常情况

  3. 性能考虑:避免在监听器中执行耗时操作

  4. 线程安全:当前实现不是线程安全的,如需多线程访问请添加同步机制

  5. 路由名称:确保路由有明确的名称,避免使用 'unknown' 作为路由名称

扩展建议

  1. 添加路由参数传递:支持传递路由参数给监听器

  2. 添加条件监听:支持基于条件的监听器注册

  3. 添加优先级机制:支持监听器的优先级排序

  4. 添加异步支持:支持异步监听器函数

  5. 添加统计功能:添加路由访问统计和分析功能

总结

RouteListenerManager 提供了一个强大而灵活的路由监听机制,通过单例模式和观察者模式的结合,实现了全局路由事件的统一管理。该设计具有良好的扩展性和维护性,能够满足大多数Flutter应用的路由监听需求。

代码如下,直接拿去,不谢。

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

/// 路由监听管理器
class RouteListenerManager {
  static final RouteListenerManager _instance = RouteListenerManager._internal();
  factory RouteListenerManager() => _instance;
  static RouteListenerManager get instance => _instance;
  RouteListenerManager._internal();

  final List<Function(String route)> _pushListeners = [];
  final List<Function(String route)> _popListeners = [];
  final List<Function(String newRoute, String oldRoute)> _replaceListeners = [];
  final List<Function(String route)> _removeListeners = [];

  /// 添加路由跳转监听器
  void addPushListener(Function(String route) listener) {
    _pushListeners.add(listener);
  }

  /// 添加路由返回监听器
  void addPopListener(Function(String route) listener) {
    _popListeners.add(listener);
  }

  /// 添加路由替换监听器
  void addReplaceListener(Function(String newRoute, String oldRoute) listener) {
    _replaceListeners.add(listener);
  }

  /// 添加路由移除监听器
  void addRemoveListener(Function(String route) listener) {
    _removeListeners.add(listener);
  }

  /// 移除路由跳转监听器
  void removePushListener(Function(String route) listener) {
    _pushListeners.remove(listener);
  }

  /// 移除路由返回监听器
  void removePopListener(Function(String route) listener) {
    _popListeners.remove(listener);
  }

  /// 移除路由替换监听器
  void removeReplaceListener(Function(String newRoute, String oldRoute) listener) {
    _replaceListeners.remove(listener);
  }

  /// 移除路由移除监听器
  void removeRemoveListener(Function(String route) listener) {
    _removeListeners.remove(listener);
  }

  /// 移除路由全部监听器
  void removeAllListener() {
    _pushListeners.clear();
    _popListeners.clear();
    _replaceListeners.clear();
    _removeListeners.clear();
  }

  /// 通知路由跳转
  void notifyPush(String route) {
    for (final listener in _pushListeners) {
      try {
        listener(route);
      } catch (e) {
        debugPrint('Route push listener error: $e');
      }
    }
  }

  /// 通知路由返回
  void notifyPop(String route) {
    for (final listener in _popListeners) {
      try {
        listener(route);
      } catch (e) {
        debugPrint('Route pop listener error: $e');
      }
    }
  }

  /// 通知路由替换
  void notifyReplace(String newRoute, String oldRoute) {
    for (final listener in _replaceListeners) {
      try {
        listener(newRoute, oldRoute);
      } catch (e) {
        debugPrint('Route replace listener error: $e');
      }
    }
  }

  /// 通知路由移除
  void notifyRemove(String route) {
    for (final listener in _removeListeners) {
      try {
        listener(route);
      } catch (e) {
        debugPrint('Route remove listener error: $e');
      }
    }
  }
}

/// 全局路由监听器
class GlobalRouteObserver extends NavigatorObserver {
  @override
  void didPush(Route<dynamic> route, Route<dynamic>? previousRoute) {
    super.didPush(route, previousRoute);
    final routeName = route.settings.name ?? 'unknown';
    debugPrint('GlobalRouteListener - 路由跳转: $routeName');
    RouteListenerManager().notifyPush(routeName);
  }

  @override
  void didPop(Route<dynamic> route, Route<dynamic>? previousRoute) {
    super.didPop(route, previousRoute);
    final routeName = route.settings.name ?? 'unknown';
    debugPrint('GlobalRouteListener - 路由返回: $routeName');
    RouteListenerManager().notifyPop(routeName);
  }

  @override
  void didReplace({Route<dynamic>? newRoute, Route<dynamic>? oldRoute}) {
    super.didReplace(newRoute: newRoute, oldRoute: oldRoute);
    if (newRoute != null && oldRoute != null) {
      final newRouteName = newRoute.settings.name ?? 'unknown';
      final oldRouteName = oldRoute.settings.name ?? 'unknown';
      debugPrint('GlobalRouteListener - 路由替换: $oldRouteName -> $newRouteName');
      RouteListenerManager().notifyReplace(newRouteName, oldRouteName);
    }
  }

  @override
  void didRemove(Route<dynamic> route, Route<dynamic>? previousRoute) {
    super.didRemove(route, previousRoute);
    final routeName = route.settings.name ?? 'unknown';
    debugPrint('GlobalRouteListener - 路由移除: $routeName');
    RouteListenerManager().notifyRemove(routeName);
  }
}
相关推荐
盗德5 小时前
为什么要用Monorepo管理前端项目?(详解)
前端·架构·代码规范
五号厂房5 小时前
ProTable 大数据渲染优化:实现高性能表格编辑
前端
右子6 小时前
理解响应式设计—理念、实践与常见误解
前端·后端·响应式设计
KaiSonng6 小时前
【前端利器】这款轻量级图片标注库让你的Web应用瞬间提升交互体验
前端
二十雨辰6 小时前
vite性能优化
前端·vue.js
明月与玄武6 小时前
浅谈 富文本编辑器
前端·javascript·vue.js
paodan6 小时前
如何使用ORM 工具,Prisma
前端
布列瑟农的星空6 小时前
重学React——memo能防止Context的额外渲染吗
前端
FuckPatience6 小时前
Vue 与.Net Core WebApi交互时路由初探
前端·javascript·vue.js