Flutter:Android杀后台后如何按需恢复表单与应用状态?
解决方案
一、仅在系统销毁Activity时持久化Bloc状态
hydrated_bloc默认全局持久化状态,要实现仅在App被后台杀死时保留状态,核心是区分正常页面退出和系统强制销毁两种场景:
监听App生命周期,标记销毁状态
在表单页面混入WidgetsBindingObserver,通过生命周期状态判断是否是系统销毁:class FormPage extends StatefulWidget { @override _FormPageState createState() => _FormPageState(); } class _FormPageState extends State<FormPage> with WidgetsBindingObserver { bool _isSystemDestroyed = false; final _formKey = GlobalKey<FormBuilderState>(); @override void initState() { super.initState(); WidgetsBinding.instance.addObserver(this); } @override void didChangeAppLifecycleState(AppLifecycleState state) { // 当App完全脱离前台(被系统销毁时会触发此状态) if (state == AppLifecycleState.detached) { _isSystemDestroyed = true; } } @override void dispose() { // 正常关闭页面时,清除Bloc的持久化数据 if (!_isSystemDestroyed) { context.read<FormBloc>().clear(); // 同时清除路由和表单数据的持久化记录 _clearPersistedData(); } WidgetsBinding.instance.removeObserver(this); super.dispose(); } Future<void> _clearPersistedData() async { final prefs = await SharedPreferences.getInstance(); await prefs.remove('last_route'); await prefs.remove('form_data'); } }配合Bloc控制持久化逻辑
给你的FormBloc添加开关,仅在系统销毁时允许序列化状态:class FormBloc extends HydratedBloc<FormEvent, FormState> { bool shouldPersist = false; FormBloc() : super(FormState.initial()) { on<FormDataUpdated>((event, emit) { emit(state.copyWith(formData: event.values)); }); } @override FormState? fromJson(Map<String, dynamic> json) { return shouldPersist ? FormState.fromJson(json) : null; } @override Map<String, dynamic>? toJson(FormState state) { return shouldPersist ? state.toJson() : null; } }在页面的
didChangeAppLifecycleState中设置开关:@override void didChangeAppLifecycleState(AppLifecycleState state) { if (state == AppLifecycleState.detached) { _isSystemDestroyed = true; context.read<FormBloc>().shouldPersist = true; } }
二、应用重启后自动跳转表单页
通过持久化路由信息,在App启动时读取并设置初始路由:
保存当前路由
在表单页面initState中持久化路由名称:@override void initState() { super.initState(); _saveCurrentRoute(); } Future<void> _saveCurrentRoute() async { final prefs = await SharedPreferences.getInstance(); // 替换为你的auto_route路由名 await prefs.setString('last_route', Routes.longFormPage); }启动时跳转目标页面
在App入口初始化路由前读取持久化数据:Future<void> main() async { WidgetsFlutterBinding.ensureInitialized(); final prefs = await SharedPreferences.getInstance(); final lastRoute = prefs.getString('last_route'); // 初始化auto_route时传入初始路由 final appRouter = AppRouter(initialRoute: lastRoute); runApp(MyApp(router: appRouter)); }
三、填充FormBuilder的表单数据
核心是让表单数据和持久化层同步,有两种实现方式:
同步表单数据到Bloc状态
利用FormBuilder的onChanged回调,实时将表单数据同步到Bloc,重启后从Bloc状态恢复:FormBuilder( key: _formKey, // 从Bloc状态读取初始值 initialValue: context.watch<FormBloc>().state.formData, onChanged: (values) { // 实时更新Bloc状态 context.read<FormBloc>().add(FormDataUpdated(values)); }, // 表单字段 child: Column( children: [ FormBuilderTextField(name: 'username'), FormBuilderDropdown(name: 'gender'), // ...其他字段 ], ), )单独持久化表单数据
如果不想依赖Bloc,可直接用SharedPreferences存储表单数据:// 系统销毁时保存表单数据 Future<void> _saveFormData() async { if (_formKey.currentState?.validate() ?? false) { final prefs = await SharedPreferences.getInstance(); await prefs.setString( 'form_data', jsonEncode(_formKey.currentState!.value), ); } } // 页面初始化时加载数据 @override void initState() { super.initState(); _loadFormData(); } Future<void> _loadFormData() async { final prefs = await SharedPreferences.getInstance(); final dataStr = prefs.getString('form_data'); if (dataStr != null) { final formData = jsonDecode(dataStr) as Map<String, dynamic>; _formKey.currentState?.patchValue(formData); } }记得在
didChangeAppLifecycleState中调用_saveFormData()。
关键验证点
- 用Android Studio的「Stop Process」模拟后台杀死应用,验证状态恢复和页面跳转是否正常
- 测试正常返回页面的场景,确保持久化数据被清除,不会干扰下次进入表单
内容的提问来源于stack exchange,提问作者Szymon Głowacki
相关产品推荐
相关产品推荐

