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);
  }
}
相关推荐
IT_陈寒17 分钟前
Vue3性能翻倍秘籍:5个Composition API技巧让你的应用快如闪电⚡
前端·人工智能·后端
Dontla19 分钟前
npm install命令介绍
前端·npm·node.js
天天向上102427 分钟前
vue2 vue3 修改elementUI和elementPlus主题颜色
前端·javascript·elementui
Zhangzy@37 分钟前
Rust Workspace 构建多项目体系
开发语言·前端·rust
通往曙光的路上37 分钟前
day23_密码加密 前端验证码 监听器 svn版本控制
前端·svn
TivonaLH40 分钟前
v-code-diff入口文件的配置
前端·javascript·vue.js
青衫码上行42 分钟前
【Java Web学习 | 第四篇】CSS(3) -背景
java·前端·学习
.生产的驴43 分钟前
React 路由权限跳转 Token判断 路由控制 登录状态控制
前端·javascript·react.js·ajax·前端框架·c#·ecmascript
美狐美颜sdk8 小时前
跨平台直播美颜sdk集成攻略:Android、iOS与Web的统一方案
android·前端·ios
Airser8 小时前
npm启动Taro框架报错
前端·npm·taro