当前位置:网站首页>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
边栏推荐
- 05个人研发的产品及推广-数据同步工具
- MySQL error reporting solution
- Example of batch update statement combining update and inner join in SQL Server
- connection reset by peer
- 远程代码执行渗透测试——B模块测试
- Xin'an Second Edition: Chapter 23 cloud computing security requirements analysis and security protection engineering learning notes
- Interpretation of Flink source code (II): Interpretation of jobgraph source code
- Display picture of DataGridView cell in C WinForm
- The NTFS format converter (convert.exe) is missing from the current system
- Case: check the empty field [annotation + reflection + custom exception]
猜你喜欢
About selenium starting Chrome browser flash back
JUnit unit test
Garbage first of JVM garbage collector
Distributed (consistency protocol) leader election (dotnext.net.cluster implements raft election)
C# WinForm系列-Button简单使用
Final review of information and network security (full version)
[elastic] elastic lacks xpack and cannot create template unknown setting index lifecycle. name index. lifecycle. rollover_ alias
07 personal R & D products and promotion - human resources information management system
【MySQL入门】第四话 · 和kiko一起探索MySQL中的运算符
C # nanoframework lighting and key esp32
随机推荐
【MySQL入门】第四话 · 和kiko一起探索MySQL中的运算符
Application service configurator (regular, database backup, file backup, remote backup)
Re signal writeup
C version selenium operation chrome full screen mode display (F11)
Detailed explanation of data types of MySQL columns
MySQL Advanced (index, view, stored procedures, functions, Change password)
Concept and basic knowledge of network layering
Distributed (consistency protocol) leader election (dotnext.net.cluster implements raft election)
The art of Engineering (1): try to package things that do not need to be exposed
connection reset by peer
Huawei certified cloud computing hica
远程代码执行渗透测试——B模块测试
[rapid environment construction] openharmony 10 minute tutorial (cub pie)
Redis installation on centos7
Start job: operation returned an invalid status code 'badrequst' or 'forbidden‘
Final review of information and network security (based on the key points given by the teacher)
关于Selenium启动Chrome浏览器闪退问题
Program counter of JVM runtime data area
信息与网络安全期末复习(完整版)
Development and practice of lightweight planning service tools