Navigator2.0页面栈恢复方案咨询:替代Navigator.restorablePush方法
在Navigator2.0中,确实有对应的页面栈状态恢复方案,但不能直接依赖Navigator1.0的restorablePush——你推测的原因是对的:Navigator2.0的页面栈完全由RouterDelegate维护的pages列表驱动,Activity销毁时如果没有持久化这个列表的状态,重建后RouterDelegate会回到初始状态,导致之前的页面栈丢失。
核心解决思路
要实现Navigator2.0的页面栈恢复,关键是持久化RouterDelegate中页面栈的状态,而不是依赖Navigator的restorable方法。具体步骤如下:
定义可序列化的页面状态模型
给每个页面创建一个包含路由名、必要参数的模型,实现序列化/反序列化逻辑,方便持久化。在RouterDelegate中管理页面状态
用这个模型列表替代直接维护Page对象,每次页面跳转时更新该列表并持久化。结合状态恢复机制与本地存储
- 用Flutter的
RestorationMixin处理配置变更(如屏幕旋转)的状态恢复。 - 用本地存储(如
SharedPreferences)处理Activity销毁后重启的状态恢复。
- 用Flutter的
代码示例
1. 页面状态模型
class PageState { final String routeName; final Map<String, dynamic>? arguments; PageState(this.routeName, this.arguments); // 序列化 Map<String, dynamic> toJson() => { 'routeName': routeName, 'arguments': arguments, }; // 反序列化 factory PageState.fromJson(Map<String, dynamic> json) => PageState( json['routeName'], json['arguments'] as Map<String, dynamic>?, ); }
2. 带状态恢复的RouterDelegate
class AppRouterDelegate extends RouterDelegate<Uri> with RestorationMixin { final _restorationId = 'app_router'; final List<PageState> _pageStates = [PageState('/', null)]; // 初始页面 // 用于Flutter内置状态恢复的可恢复列表 final RestorableList<PageState> _restorablePageStates = RestorableList<PageState>(defaultValue: []); @override String? get restorationId => _restorationId; @override void restoreState(RestorationBucket? oldBucket, bool initialRestore) { registerForRestoration(_restorablePageStates, 'page_states_list'); // 从本地存储恢复页面栈(处理Activity销毁重启) _loadSavedPageStates(); } // 从SharedPreferences加载持久化的页面状态 Future<void> _loadSavedPageStates() async { final prefs = await SharedPreferences.getInstance(); final jsonStrings = prefs.getStringList('saved_page_states'); if (jsonStrings != null) { _pageStates.clear(); _pageStates.addAll(jsonStrings .map((json) => PageState.fromJson(jsonDecode(json))) .toList()); _restorablePageStates.value = _pageStates; notifyListeners(); } } // 持久化页面状态到SharedPreferences Future<void> _savePageStates() async { final prefs = await SharedPreferences.getInstance(); final jsonStrings = _pageStates .map((state) => jsonEncode(state.toJson())) .toList(); await prefs.setStringList('saved_page_states', jsonStrings); } @override Widget build(BuildContext context) { return Navigator( pages: _pageStates.map((state) { switch (state.routeName) { case '/': return MaterialPage(key: const ValueKey('/'), child: const HomePage()); case '/detail': return MaterialPage( key: ValueKey('/detail-${state.arguments?['id']}'), child: DetailPage(arguments: state.arguments), ); default: return MaterialPage(key: const ValueKey('/404'), child: const NotFoundPage()); } }).toList(), onPopPage: (route, result) { if (!route.didPop(result)) return false; if (_pageStates.length > 1) { _pageStates.removeLast(); _savePageStates(); notifyListeners(); } return true; }, ); } // 自定义跳转方法,更新页面栈并持久化 void pushPage(String routeName, [Map<String, dynamic>? arguments]) { _pageStates.add(PageState(routeName, arguments)); _savePageStates(); notifyListeners(); } // 实现RouterDelegate的其他必要方法 @override Future<void> setNewRoutePath(Uri configuration) async { // 处理深层链接逻辑(可选) } @override Uri? get currentConfiguration => Uri.parse(_pageStates.last.routeName); }
注意事项
- 禁止混用Navigator1.0的
push/restorablePush方法:这些方法不会更新RouterDelegate的pages列表,导致页面栈状态不一致。 - 页面状态要精简:只存储必要的参数(如ID、路由名),不要存储大数据或上下文对象。
- 区分场景:
RestorationMixin适合处理配置变更(如旋转屏幕),本地存储适合处理App重启、Activity销毁后的恢复。
内容的提问来源于stack exchange,提问作者Matsuyan
相关产品推荐
相关产品推荐

