当前位置:网站首页>FlutterWeb浏览器刷新后无法回退的解决方案
FlutterWeb浏览器刷新后无法回退的解决方案
2022-07-06 09:38:00 【代码不难写】
问题
在Flutter开发的网页运行时,浏览器刷新网页后,虽然会显示刷新前的页面(前提是用静态路由跳转),但这时调用Navigator.pop方法是回不到上一页的,包括点击浏览器的回退按钮也是无效的(地址栏中的url会变,页面不会变)。
原因
当浏览器刷新时,Flutter引擎会重新启动,并加载当前页面,也就是说,刷新后的Flutter内存中所有静态变量都被初始化,页面栈内之前的页面记录都未保留,只有当前的页面。就像是浏览网页时,把其中一页的网址拷出来,在新的标签页再次打开。
解决方案
(一)思路
知道什么原因引起的,就针对性解决。页面栈记录丢失,那么就代码中自己维护一套备用栈,监听页面路由,每次进入新页面时,记录当前页面的URL,当退出时,删除记录的URL,在浏览器刷新栈记录失效时,帮助回退到上一页。
(二)方案优缺点
优点: 可实现回退效果无异常,调用Navigator.pop方法或点击浏览器回退按钮都支持;
缺点: Navigator.pushName().then的回调无法生效,因为是重新生成的上一页,所以并不会调用回调;回退后的页面中的临时数据都会消失,比如输入框内的内容,成员变量等;跳转必须用静态路由的方式,并且传参要用Uri包裹,不能用构造函数传参。
实现
1. Web本地存储工具—localStorage
localStorage是在html包下window中的一个存储对象,以key、value的形式进行存储
// 导包
import 'dart:html' as html;
// 使用方式
html.window.localStorage["key"] = "value"
对存储工具的封装这里就不写到文章里了,根据实现业务情况去封装,方便调用就行。
2. 栈记录工具类RouterHistory
这是一个栈记录工具,主要作用是注册监听,添加删除记录等。
/// DB()为封装好的本地数据库
class RouterHistory {
/// 监听浏览器刷新前的回调
static Function(html.Event event)? _beforeUnload;
/// 监听浏览器回退时的回调
static Function(html.Event event)? _popState;
/// 目前页面是否被刷新过
static bool isRefresh = false;
/// 初始化与注册监听
static void register() {
// 刷新时回调
_beforeUnload = (event) {
// 本地记录,标记成"已刷新"
DB(DBKey.isRefresh).value = true;
// 移除刷新前的实例的监听
html.window.removeEventListener('beforeunload', _beforeUnload);
html.window.removeEventListener('popstate', _popState);
};
// 浏览器回退按钮回调
_popState = (event) {
// 页面被刷新,触发备用回调
if (isRefresh) {
_back(R.currentContext); //R.currentContext 为当前页面的Context
}
};
// 添加监听
html.window.addEventListener('beforeunload', _beforeUnload);
html.window.addEventListener('popstate', _popState);
// 从本地数据库中取出"刷新"标记
isRefresh = DB(DBKey.isRefresh).get(false);
// 如果未被刷新,清除上次备用栈中的历史记录
if (!isRefresh) {
clean();
}
// 还原本地库中的刷新标记
DB(DBKey.isRefresh).value = false;
}
static bool checkBack(currentContext) {
// 是否能正常 pop
if (Navigator.canPop(currentContext)) {
return true;
}
// 不能则启用备用栈
_back(currentContext);
return false;
}
// 返回
static void _back(currentContext) {
List history = get();
if (history.length > 1) {
history.removeLast();
set(history);
//跳转至上一页并关闭当前页
Navigator.of(currentContext).popAndPushNamed(history.last);
}
}
// 添加记录
static add(String? path) {
if (path == null) return;
List history = get();
if (history.contains(path)) return;
history.add(path);
set(history);
}
// 删除记录
static remove(String? path) {
if (path == null) return;
List history = get();
history.remove(path);
set(history);
}
// 设置备用栈数据
static String set(List<dynamic> history) => DB(DBKey.history).value = json.encode(history);
// 取出备用栈数据
static get() => json.decode(DB(DBKey.history).get('[]'));
// 清除备用栈
static clean() => DB(DBKey.history).value = '[]';
}
3. 监听Flutter路由
自定义类并实现NavigatorObserver,并将实现类放在MaterialApp中的navigatorObservers参数中。
// 实现类
class HistoryObs extends NavigatorObserver {
@override
void didPush(Route<dynamic> route, Route<dynamic>? previousRoute) {
// 存路由信息
RouterHistory.add(route.settings.name);
}
@override
void didPop(Route<dynamic> route, Route<dynamic>? previousRoute) {
// 删路由信息
RouterHistory.remove(route.settings.name);
}
}
// 设置监听
MaterialApp(
......
navigatorObservers: [ HistoryObs() ],
......
)
4. 路由方法封装
跳转方法必须为静态路由,以保证参数和路径都能在url中,才可实现回退效果
/// 替换 Navigator.pop ,
static pop() {
// 检测是否能正常返回,不能则返回FALSE
if (RouterHistory.checkBack(currentContext)) {
Navigator.pop(currentContext);
}
}
/// 静态路由跳转
static Future toName(String pageName, {Map<String, dynamic>? params}) {
// 封装路径以及参数
var uri = Uri(scheme: RoutePath.scheme, host: pageName, queryParameters: params ?? {});
return Navigator.of(currentContext).pushNamed(uri.toString());
}
5. 初始化位置
放在MaterialApp外层的build中,或initState中即可。
@override
void initState() {
super.initState();
RouterHistory.register();
}
@override
Widget build(BuildContext context) {
// 或 RouterHistory.register();
return MaterialApp(
navigatorObservers: [MiddleWare()],
);
}
以上就是该方案的关键代码
最后
该方案只是能解决问题,但不是最好的解决方案。有更好的解决方案欢迎留言~
Flutter官方的Navigator 2.0 虽然能实现回退,本质上也是跳转了新页面,并造成栈内记录混乱,不能像真正的web一样,感兴趣的同学可以自行了解下Navigator 2.0。
Navigator2.0在浏览器回退按钮的处理上又与Navigator1.0不同,点击回退按钮时Navigator2.0并不是执行pop操作,而是执行setNewRoutePath操作,本质上应该是从浏览器的history中获取上一个页面的url,然后重新加载。这样确实解决了刷新后回退的问题,因为刷新后浏览器的history并未丢失,但是也导致了文章中我们提到的flutter中的页面栈混乱的问题。
如果你进阶的路上缺乏方向,可以扫描下方二维码加入我们的圈子和安卓开发者们一起学习交流!
-以下全部内容都可以在微信中获取!
Android进阶学习全套手册
Android对标阿里P7学习视频
BATJ大厂Android高频面试题
作者:苏啵曼
链接:https://juejin.cn/post/7114848130004156446
边栏推荐
- 基于Infragistics.Document.Excel导出表格的类
- 07 personal R & D products and promotion - human resources information management system
- MySQL Advanced (index, view, stored procedures, functions, Change password)
- PySpark算子处理空间数据全解析(5): 如何在PySpark里面使用空间运算接口
- Kali2021 installation and basic configuration
- Wordcloud colormap color set and custom colors
- Pyspark operator processing spatial data full parsing (5): how to use spatial operation interface in pyspark
- [reverse intermediate] eager to try
- 华为认证云计算HICA
- Final review of information and network security (based on the key points given by the teacher)
猜你喜欢
PySpark算子处理空间数据全解析(5): 如何在PySpark里面使用空间运算接口
C#版Selenium操作Chrome全屏模式显示(F11)
The NTFS format converter (convert.exe) is missing from the current system
集成开发管理平台
Yarn: unable to load file d:\programfiles\nodejs\yarn PS1, because running scripts is prohibited on this system
The most complete tcpdump and Wireshark packet capturing practice in the whole network
Huawei certified cloud computing hica
Wu Jun's trilogy insight (V) refusing fake workers
Vscode matches and replaces the brackets
基于LNMP部署flask项目
随机推荐
Redis installation on centos7
Wordcloud colormap color set and custom colors
yarn : 无法加载文件 D:\ProgramFiles\nodejs\yarn.ps1,因为在此系统上禁止运行脚本
【逆向中级】跃跃欲试
Binary search strategy
Summary of study notes for 2022 soft exam information security engineer preparation
Essai de pénétration du Code à distance - essai du module b
[mmdetection] solves the installation problem
MySQL basic addition, deletion, modification and query of SQL statements
JVM class loading subsystem
How does wechat prevent withdrawal come true?
Solid principle
【Elastic】Elastic缺少xpack无法创建模板 unknown setting index.lifecycle.name index.lifecycle.rollover_alias
About selenium starting Chrome browser flash back
Remote code execution penetration test - B module test
信息与网络安全期末复习(完整版)
关于Selenium启动Chrome浏览器闪退问题
Debug xv6
Akamai talking about risk control principles and Solutions
Application service configurator (regular, database backup, file backup, remote backup)