Flutter笔记:路由观察者
作者:李俊才 (jcLee95):https://blog.csdn.net/qq_28550263
邮箱 :291148484@163.com
本文地址:https://blog.csdn.net/qq_28550263/article/details/134572181
目 录
1. 概述
路由观察者(Route Observer)是一个监听路由(页面)变化的工具。在Flutter应用中,我们经常需要监听路由的变化,例如当用户从一个页面跳转到另一个页面时,我们可能需要执行一些操作,如数据统计、页面切换动画等,这时就需要用到路由观察者。
路由观察者的定义:路由观察者是一个抽象类,它定义了一些方法,这些方法可以在路由发生变化时被调用。我们可以通过继承路由观察者类并实现这些方法,来创建自己的路由观察者。
路由观察者的作用:路由观察者的主要作用是监听路由的变化,当路由发生变化时,路由观察者的相应方法会被调用,我们可以在这些方法中执行需要的操作。
路由观察者的使用场景:路由观察者可以用于各种需要监听路由变化的场景,例如数据统计、页面切换动画、用户行为跟踪等。
总的来说,路由观察者是Flutter中一个非常重要的工具,它可以帮助我们更好地理解和控制路由的变化。
2. 路由观察者的创建和使用
2.1 NavigatorObserver类的介绍
在Flutter中,路由观察者是通过继承NavigatorObserver类来创建的。NavigatorObserver是一个抽象类,它定义了一些方法,这些方法会在路由发生变化时被调用。例如,didPush方法会在新的路由被推送到导航器时被调用,didPop方法会在路由从导航器中弹出时被调用。
2.2 创建一个NavigatorObserver的子类
要创建一个路由观察者,我们需要创建一个NavigatorObserver 的子类,并实现它的方法。下面是一个简单的例子:
class MyRouteObserver extends NavigatorObserver {void didPush(Route route, Route previousRoute) {super.didPush(route, previousRoute);print('didPush ${route.settings.name}');}void didPop(Route route, Route previousRoute) {super.didPop(route, previousRoute);print('didPop ${route.settings.name}');}
}
在这个例子中,我们创建了一个名为 MyRouteObserver 的路由观察者,它会在路由被推送和弹出时打印路由的名称。
2.3 将路由观察者添加到MaterialApp或WidgetsApp
创建了路由观察者后,我们需要将它添加到 MaterialApp 或 WidgetsApp 中,这样它才能监听到路由的变化。这可以通过设置navigatorObservers
属性来实现:
void main() {runApp(MyApp());
}class MyApp extends StatelessWidget {final MyRouteObserver _myRouteObserver = MyRouteObserver();Widget build(BuildContext context) {return MaterialApp(title: 'Flutter Demo',navigatorObservers: [_myRouteObserver],home: MyHomePage(),);}
}
在这个例子中,我们创建了一个 MyRouteObserver 的实例,并将它添加到了 MaterialApp 的navigatorObservers中。这样,MyRouteObserver 就能监听到所有路由的变化了。
3. 路由观察者的方法
路由观察者的方法主要包括 didPush
,didPop
,didRemove
和 didReplace
等。下面我们来详细介绍这些方法。
3.1 didPush
didPush
方法会在新的路由被推送到导航器时被调用。它有两个参数:route
和 previousRoute
,分别表示新推送的路由和之前的路由。
使用场景:当我们需要在新的路由被推送时执行一些操作时,可以在didPush方法中实现。
3.2 didPop
didPop
方法会在路由从导航器中弹出时被调用。它的参数和 didPush
方法相同。
使用场景:当我们需要在路由被弹出时执行一些操作时,可以在didPop方法中实现。
3.3 didRemove
didRemove
方法会在路由被从导航器中移除时被调用。它有两个参数:route
和 previousRoute
,分别表示被移除的路由和之前的路由。
使用场景:当我们需要在路由被移除时执行一些操作时,可以在didRemove方法中实现。
3.4 didReplace
didReplace 方法会在一个路由被另一个路由替换时被调用。它有两个参数:newRoute 和 oldRoute,分别表示新的路由和被替换的路由。
使用场景:当我们需要在路由被替换时执行一些操作时,可以在didReplace方法中实现。
下面是一个使用这些方法的例子:
在这个例子中,我们在每个方法中都打印了相关的信息,这样我们就可以清楚地看到路由的变化。
class MyRouteObserver extends NavigatorObserver {void didPush(Route route, Route previousRoute) {super.didPush(route, previousRoute);print('didPush ${route.settings.name}');}void didPop(Route route, Route previousRoute) {super.didPop(route, previousRoute);print('didPop ${route.settings.name}');}void didRemove(Route route, Route previousRoute) {super.didRemove(route, previousRoute);print('didRemove ${route.settings.name}');}void didReplace({Route newRoute, Route oldRoute}) {super.didReplace(newRoute: newRoute, oldRoute: oldRoute);print('didReplace ${oldRoute.settings.name} with ${newRoute.settings.name}');}
}
4. 路由观察者的应用
路由观察者在 Flutter 应用中有很多实际的应用场景,例如用于用户行为跟踪,页面切换动画等。
4.1 用户行为跟踪
在很多应用中,我们需要跟踪用户的行为,例如用户打开了哪些页面,停留在每个页面的时间等。这时,我们可以使用路由观察者来实现。
当用户打开一个新的页面时,didPush
方法会被调用,我们可以在这个方法中记录用户打开这个页面的时间;当用户关闭一个页面时,didPop
方法会被调用,我们可以在这个方法中记录用户关闭这个页面的时间。通过这种方式,我们就可以跟踪用户在每个页面的停留时间。
4.2 页面切换动画
在一些应用中,我们希望在页面切换时有一些特殊的动画效果。这时,我们也可以使用路由观察者来实现。
我们可以在 didPush
和 didPop
方法中添加动画效果。例如,当用户打开一个新的页面时,我们可以在 didPush
方法中添加一个淡入效果;当用户关闭一个页面时,我们可以在 didPop
方法中添加一个淡出效果。
下面是一个使用路由观察者来实现用户行为跟踪的例子:
class MyRouteObserver extends NavigatorObserver {void didPush(Route route, Route previousRoute) {super.didPush(route, previousRoute);print('User opened ${route.settings.name}');// 这里我们可以启动一个计时器来跟踪用户在这个页面上停留的时间。}void didPop(Route route, Route previousRoute) {super.didPop(route, previousRoute);print('User closed ${route.settings.name}');// 在这里,我们可以停止计时器,并获得用户在此页面停留的时间。}
}
在这个例子中,我们在 didPush
和 didPop
方法中分别打印了用户打开和关闭页面的信息,并且提到了如何使用计时器来跟踪用户在每个页面的停留时间。
5. 路由观察者的限制和注意事项
虽然路由观察者是一个非常强大的工具,但在使用过程中也有一些限制和需要注意的事项。
5.1 限制
仅仅监听 Navigator 进行的路由变化
- 路由观察者只能监听到通过 Navigator 进行的路由变化,如果路由变化是通过其他方式(例如直接修改组件的状态)进行的,那么路由观察者是无法监听到的。
PopScope
- 路由观察者的方法是在路由变化后被调用的,因此它不能阻止路由的变化。如果你需要在路由变化前进行一些操作(例如询问用户是否确定要离开当前页面),那么你需要使用其他的方法,例如 PopScope( WillPopScope 已经被废弃,使用PopScope替代)。
关于 PopScope 这里补充一个案例分析:
import 'package:flutter/material.dart';void main() => runApp(const NavigatorPopHandlerApp());class NavigatorPopHandlerApp extends StatelessWidget {const NavigatorPopHandlerApp({super.key});Widget build(BuildContext context) {return MaterialApp(// 设置初始路由为 '/home'initialRoute: '/home',// 定义路由表routes: <String, WidgetBuilder>{'/home': (BuildContext context) => const _HomePage(),'/two': (BuildContext context) => const _PageTwo(),},);}
}
class _HomePage extends StatefulWidget {const _HomePage();State<_HomePage> createState() => _HomePageState();
}// 首页的状态组件
class _HomePageState extends State<_HomePage> {Widget build(BuildContext context) {return Scaffold(body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: <Widget>[const Text('Page One'), // 显示 "Page One" 文字TextButton(onPressed: () {Navigator.of(context).pushNamed('/two'); // 点击按钮后跳转到第二个页面},child: const Text('Next page'), // 显示 "Next page" 文字),],),),);}
}
// 第二个页面的组件
class _PageTwo extends StatefulWidget {const _PageTwo();State<_PageTwo> createState() => _PageTwoState();
}// 第二个页面的状态组件
class _PageTwoState extends State<_PageTwo> {// 显示一个对话框,询问用户是否确定离开void _showBackDialog() {showDialog<void>(context: context,builder: (BuildContext context) {return AlertDialog(title: const Text('Are you sure?'), // 对话框标题content: const Text('Are you sure you want to leave this page?', // 对话框内容),actions: <Widget>[TextButton(style: TextButton.styleFrom(textStyle: Theme.of(context).textTheme.labelLarge,),child: const Text('Nevermind'), // "Nevermind" 按钮onPressed: () {Navigator.pop(context); // 点击后关闭对话框},),TextButton(style: TextButton.styleFrom(textStyle: Theme.of(context).textTheme.labelLarge,),child: const Text('Leave'), // "Leave" 按钮onPressed: () {Navigator.pop(context); // 点击后关闭对话框Navigator.pop(context); // 并返回上一个页面},),],);},);}Widget build(BuildContext context) {return Scaffold(body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: <Widget>[const Text('Page Two'), // 显示 "Page Two" 文字PopScope(canPop: false,onPopInvoked: (bool didPop) {if (didPop) {return;}_showBackDialog(); // 当用户尝试离开时,显示对话框},child: TextButton(onPressed: () {_showBackDialog(); // 点击按钮后显示对话框},child: const Text('Go back'), // 显示 "Go back" 文字),),],),),);}
}
这段代码是Flutter官方给出的一个案例,它包含两个页面,用户可以在这两个页面之间导航。当用户尝试离开第二个页面时,会弹出一个对话框询问用户是否确定离开。
5.2 注意事项
-
在使用路由观察者时,需要注意不要在路由观察者的方法中进行过于复杂的操作,因为这可能会影响到路由的性能。如果需要进行复杂的操作,建议在另一个异步任务中进行。
-
在使用路由观察者时,需要注意正确地管理路由观察者的生命周期。如果一个路由观察者被销毁了,但是你仍然试图在它的方法中访问一些资源,那么可能会导致错误。
-
在使用路由观察者时,需要注意处理好异常。因为路由观察者的方法是在路由变化后被调用的,如果在这些方法中发生了异常,那么可能会导致应用崩溃。
相关文章:
Flutter笔记:路由观察者
Flutter系列 路由观察者 作者:李俊才 (jcLee95):https://blog.csdn.net/qq_28550263 邮箱 :291148484163.com 本文地址:https://blog.csdn.net/qq_28550263/article/details/134572181 目 录 1. 概述2. 路由…...

【驱动】串口驱动分析(三)-serial driver
简介 前两节我们介绍串口驱动的框架和tty core部分。这节我们介绍和硬件紧密相关的串口驱动部分。 UART驱动部分依赖于硬件平台,而TTY驱动和具体的平台无关。虽然UART部分依赖于平台,但是不管是哪个硬件平台,驱动的思路都是一致的ÿ…...
(C++20) constinit常量初始化
文章目录 由来constinit 常量初始化常量初始化 ! 初始化常量初始化声明静态存储对象非初始化声明thread_local END 由来 在C多文件编译中会出现一个常见的问题,叫做静态初始化顺序问题。Static Initialization Order Fiasco。 比如现在有两个文件,其中…...

python实现获取aws route53域名信息
最近由于工作原因接触到aws的服务,我需要实时获取所有的域名信息,用于对其进行扫描,因此写了一个自动化爬取脚本 给需要的人分享。 1.基础准备 代码环境:python3 第三方库:boto3 (安装方法pip install…...
Linux_Linux终端常用快捷键
Linux命令行核心常用快捷键是一些在终端中使用的快捷键组合,用于提高命令行操作的效率。下面是这些快捷键的原理详细解释、使用场景解释 Ctrl A :将光标移动到命令行的开头。这个快捷键的原理是发送一个控制序列到终端,告诉终端将光标移动到…...

Neo4j 数据库管理 数据备份与恢复(头歌)
文章目录 第1关:数据备份与恢复任务描述相关知识数据备份数据导入 编程要求测试说明答案测试前准备Cypher 代码数据备份与导入 第1关:数据备份与恢复 任务描述 本关任务:熟练掌握数据备份与恢复。 相关知识 为了完成本关任务,…...
TCP传输的三次握手四次挥手策略
TCP传输的三次握手四次挥手策略如下: 第一次握手:客户端发送一个带有SYN标志的数据包给服务器,并记为SYN_Client。第二次握手:服务器收到SYN_Client后,向客户端发送一个带有SYN和ACK标志的数据包,记为SYN_…...

在gitlab上使用server_hooks
文章目录 1. 前置条件2. Git Hook2.1 Git Hook 分为两部分:本地和远程2.1.1 本地 Git Hook,由提交和合并等操作触发:2.1.2 远程 Git Hook,运行在网络操作上,例如接收推送的提交: 3. 操作步骤3.1 对所有的仓…...

【云原生系列】Kubernetes知识点
目录 概念 基础架构 单master节点 多master节点 组件 Master节点核心组件 其他组件 请求发送流程 插件 核心资源 调度资源 Pod 创建pod组件间调用流程 pod生命周期: 初始化容器 镜像拉取策略 重启策略 钩子函数 探针 探针的实现方式 DownwardAP…...
Hugging-Face报错锦囊(不断更新)
requests.exceptions.SSLError: (MaxRetryError(“HTTPSConnectionPool(host‘huggingface.co’, port443): Max retries exceeded with url: /api/models/bert-base-chinese (Caused by SSLError(SSLCertVerificationError(1, ‘[SSL: CERTIFICATE_VERIFY_FAILED] certificate…...

Redis核心数据结构
目录 五种基础数据结构 string hash list set zset 用zset实现微博热搜 scan遍历 高频问题 五种基础数据结构 string 单个赋值set 批量赋值/取值 msetmget 设置不存在字符串setnx, 如果不存在, 则设置成功返回1, 如果存在返回0, 可以当做分布式锁 删除值 设置过期时…...
Redis 如何批量删除指定前缀的Key
批量删除指定前缀的Key有两中方法,一种是借助 redis-cli,另一种是通过 SCAN 命令来遍历所有匹配前缀的 key,并使用 DEL 命令逐个删除它们。 redis-cli 使用 Redis 自带的 redis-cli 命令行工具,你可以通过以下方式批量删除指定前…...

如何熟练使用vim工具?
🎈个人主页:🎈 :✨✨✨初阶牛✨✨✨ 🐻推荐专栏1: 🍔🍟🌯C语言初阶 🐻推荐专栏2: 🍔🍟🌯C语言进阶 🔑个人信条: 🌵知行合一 …...

ClassNotFoundException: org.apache.hive.spark.client.Job
hive使用的是3.13版本,spark是3.3.3支持hadoop3.x hive将engine从mr改成spark,通过beeline执行insert、delete时一直报错,sparkTask rpc关闭, 查看yarn是出现ClassNotFoundException: org.apache.hive.spark.client.Job。 开始…...

《合成孔径雷达成像算法与实现》_使用CS算法对RADARSAT-1数据进行成像
CSA 简介:Chirp Scaling 算法 (简称 CS 算法,即 CSA) 避免了 RCMC 中的插值操作。该算法基于 Scaling 原理,通过对 chirp 信号进行频率调制,实现了对信号的尺度变换或平移。基于这种原理,可以通过相位相乘代替时域插值…...

GCN01——Ubuntu中设置vivado编辑器为vscode
确定vscode位置 在命令行中输入 which code得到文件地址 进入文件夹后可看到,这是个链接文件,不过无所谓,就用这个地址就行 设置Text Editor 打开setting选择右侧text editor 这里说明了如何进行设置 将自己的地址加进去就行 /usr/share…...
Android 11.0 软硬键盘同时使用的兼容(软键盘与内置物理键盘共存)
1.概述 在11.0的系统rom产品定制化开发总,在有些设备上,如果外接了USB扫描枪之类的设备,当插入USB扫描枪以后,然后点击输入调用输入法的时候,没有反应,但是拔掉USB扫描枪以后,输入法又能正常使用,这说明和输入法起冲突了,询问了好多同时,说可能把会把USB扫描枪识别为…...
ARM安全架构——为复杂软件提供保护
目录 一、概述 二、栈溢出和执行权限 三、面向返回的编程ROP 四、面向跳转的编程(JOP) 五、将这些技术应用于实际代码 七、检查你的知识...
提升网页交互体验的秘密武器——防抖和节流
说在前面 在现代Web开发中,提高网页性能是至关重要的。本文介绍了防抖和节流这两种常用的性能优化技术,通过控制函数的执行频率,有效减少不必要的计算和网络请求,从而提升用户体验和页面加载速度。 函数节流 节流是指限制一个函数…...

HX3002入耳检测光感驱动调试-感0x08 寄存器溢出,不变化错误问题解决方法
是否需要申请加入数字音频系统研究开发交流答疑群(课题组)?可加我微信hezkz17, 本群提供音频技术答疑服务,+群赠送语音信号处理降噪算法,蓝牙耳机音频,DSP音频项目核心开发资料, 读取光感0x08 寄存器溢出,不变化错误问题?原因 原因:没有读取到0x08数据,没有读0x…...

SpringBoot-17-MyBatis动态SQL标签之常用标签
文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...
React 第五十五节 Router 中 useAsyncError的使用详解
前言 useAsyncError 是 React Router v6.4 引入的一个钩子,用于处理异步操作(如数据加载)中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误:捕获在 loader 或 action 中发生的异步错误替…...
质量体系的重要
质量体系是为确保产品、服务或过程质量满足规定要求,由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面: 🏛️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限,形成层级清晰的管理网络…...

ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放
简介 前面两期文章我们介绍了I2S的读取和写入,一个是通过INMP441麦克风模块采集音频,一个是通过PCM5102A模块播放音频,那如果我们将两者结合起来,将麦克风采集到的音频通过PCM5102A播放,是不是就可以做一个扩音器了呢…...
镜像里切换为普通用户
如果你登录远程虚拟机默认就是 root 用户,但你不希望用 root 权限运行 ns-3(这是对的,ns3 工具会拒绝 root),你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案:创建非 roo…...

SpringCloudGateway 自定义局部过滤器
场景: 将所有请求转化为同一路径请求(方便穿网配置)在请求头内标识原来路径,然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...
《C++ 模板》
目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板,就像一个模具,里面可以将不同类型的材料做成一个形状,其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式:templa…...
在QWebEngineView上实现鼠标、触摸等事件捕获的解决方案
这个问题我看其他博主也写了,要么要会员、要么写的乱七八糟。这里我整理一下,把问题说清楚并且给出代码,拿去用就行,照着葫芦画瓢。 问题 在继承QWebEngineView后,重写mousePressEvent或event函数无法捕获鼠标按下事…...

Linux 中如何提取压缩文件 ?
Linux 是一种流行的开源操作系统,它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间,使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的,要在 …...

STM32---外部32.768K晶振(LSE)无法起振问题
晶振是否起振主要就检查两个1、晶振与MCU是否兼容;2、晶振的负载电容是否匹配 目录 一、判断晶振与MCU是否兼容 二、判断负载电容是否匹配 1. 晶振负载电容(CL)与匹配电容(CL1、CL2)的关系 2. 如何选择 CL1 和 CL…...