Flutter之路由监听器

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应用的路由监听需求。

相关推荐
张元清18 小时前
React 鼠标追踪与交互效果实战
前端·javascript·面试
MinterFusion18 小时前
HTML DOM元素的定位问题
前端·css·html
2301_8227032018 小时前
开源鸿蒙跨平台Flutter开发:非侵入式血压预估:基于 HRV 与脉搏波的建模与实现
flutter·开源·harmonyos
落魄江湖行19 小时前
入门篇六 Nuxt4错误处理:给应用装个安全气囊
前端·typescript·nuxt4
薛定猫AI19 小时前
【技术干货】用 design.md 驯服 AI 生成前端:从 Awesome Design 到工程化落地实践
前端·人工智能
kyriewen19 小时前
你的JS代码总在半夜崩溃?TypeScript来“上保险”了
前端·javascript·typescript
一直在想名19 小时前
Flutter 框架跨平台鸿蒙开发 - 胶片相机模拟
数码相机·flutter·华为·harmonyos
iReachers19 小时前
HTML打包EXE配置管理教程:多项目打包设置一键保存、加载与切换
java·前端·javascript
武藤一雄19 小时前
WPF中ViewModel之间的5种通讯方式
开发语言·前端·microsoft·c#·wpf
霍理迪19 小时前
Vue路由——route
前端