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…...

TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...
服务器硬防的应用场景都有哪些?
服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式,避免服务器受到各种恶意攻击和网络威胁,那么,服务器硬防通常都会应用在哪些场景当中呢? 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...

相机从app启动流程
一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...
leetcodeSQL解题:3564. 季节性销售分析
leetcodeSQL解题:3564. 季节性销售分析 题目: 表:sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南
🚀 C extern 关键字深度解析:跨文件编程的终极指南 📅 更新时间:2025年6月5日 🏷️ 标签:C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言🔥一、extern 是什么?&…...
Xen Server服务器释放磁盘空间
disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...
管理学院权限管理系统开发总结
文章目录 🎓 管理学院权限管理系统开发总结 - 现代化Web应用实践之路📝 项目概述🏗️ 技术架构设计后端技术栈前端技术栈 💡 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 🗄️ 数据库设…...
MySQL 8.0 事务全面讲解
以下是一个结合两次回答的 MySQL 8.0 事务全面讲解,涵盖了事务的核心概念、操作示例、失败回滚、隔离级别、事务性 DDL 和 XA 事务等内容,并修正了查看隔离级别的命令。 MySQL 8.0 事务全面讲解 一、事务的核心概念(ACID) 事务是…...
【LeetCode】3309. 连接二进制表示可形成的最大数值(递归|回溯|位运算)
LeetCode 3309. 连接二进制表示可形成的最大数值(中等) 题目描述解题思路Java代码 题目描述 题目链接:LeetCode 3309. 连接二进制表示可形成的最大数值(中等) 给你一个长度为 3 的整数数组 nums。 现以某种顺序 连接…...
关于uniapp展示PDF的解决方案
在 UniApp 的 H5 环境中使用 pdf-vue3 组件可以实现完整的 PDF 预览功能。以下是详细实现步骤和注意事项: 一、安装依赖 安装 pdf-vue3 和 PDF.js 核心库: npm install pdf-vue3 pdfjs-dist二、基本使用示例 <template><view class"con…...