Flutter如何判断StatelessWidget页面前后台 仅前台弹出AlertDialog
问题
如何判断StatelessWidget类型页面处于前台/后台状态,避免页面在后台时弹出AlertDialog,仅当页面处于前台时展示对话框。
以下是基于hooks_riverpod编写的原有实现代码:
final _provider = provider801x; class MyPage801x extends HookConsumerWidget { MyPage801x({Key? key}) : super(key: key); @override Widget build(BuildContext context, WidgetRef ref) { final String? message = ref.watch(_provider).message; if (message != null) { ref.read(_provider).done(); showResult(context, message); // 后台时不希望触发弹框 } return Scaffold( appBar: AppBar( title: Text('main screen'), ), body: Container(), ); } Future<void> showResult(BuildContext context, String message) async { Future.delayed(Duration(milliseconds: 500), () async { await showOKOnlyDialog(context, message: message); }); } }
final provider801x = ChangeNotifierProvider.autoDispose((ref) => Notifier801x(ref)); class Notifier801x extends ChangeNotifier { Notifier801x(this._ref) { _iapManager = IAPManager4Android(); _refreshDataset(); _iapListener = _iapManager.onChangedIAP.listen((IAPTransactionStateEnum state) async { _message = state.message! + ' @801x'; notifyListeners(); }); } String? _message = null; String? get message => _message; void done() { _message = null; } void _refreshDataset() { // 拉取数据 notifyListeners(); } }
实现方案
原有代码存在两个核心问题:
- 未做前后台状态判断,消息触发时不管页面是否可见都执行弹框逻辑
- 直接在build方法同步流程中触发弹框,属于build阶段执行副作用,会引发框架报错,且build多次触发时会重复弹框
通过应用生命周期状态+页面路由可见性双重校验即可实现需求,适配HookConsumerWidget这类无状态组件场景,无需改写成StatefulWidget:
- 应用级校验:判断应用是否处于
AppLifecycleState.resumed前台可交互状态,排除应用切后台的场景 - 页面级校验:判断当前页面对应的路由是否为栈顶路由,排除当前页面被其他页面覆盖的场景
改造后代码
final _provider = provider801x; class MyPage801x extends HookConsumerWidget { MyPage801x({Key? key}) : super(key: key); @override Widget build(BuildContext context, WidgetRef ref) { // 通过flutter_hooks内置hook直接获取应用生命周期状态,自动完成监听注册/释放 final appLifecycleState = useAppLifecycleState(); final message = ref.watch(_provider).message; // 用useEffect处理副作用逻辑,仅当message变化时触发,避免build重复执行 useEffect(() { if (message == null) return null; ref.read(_provider).done(); // 第一次校验:应用在前台 + 当前页面是路由栈顶层可见页面 final isPageOnTop = ModalRoute.of(context)?.isCurrent ?? false; if (appLifecycleState == AppLifecycleState.resumed && isPageOnTop) { // 延后一帧执行弹框,避开build流程 WidgetsBinding.instance.addPostFrameCallback((_) { showResult(context, message); }); } return null; }, [message]); return Scaffold( appBar: AppBar( title: const Text('main screen'), ), body: Container(), ); } Future<void> showResult(BuildContext context, String message) async { Future.delayed(const Duration(milliseconds: 500), () async { // 第二次校验:覆盖延迟等待期间用户切后台、跳转其他页面的临界场景 final isPageOnTop = ModalRoute.of(context)?.isCurrent ?? false; final isAppForeground = WidgetsBinding.instance.lifecycleState == AppLifecycleState.resumed; if (isPageOnTop && isAppForeground) { await showOKOnlyDialog(context, message: message); } }); } }
状态层Notifier代码无需修改,页面可见性判断逻辑放在UI层即可,符合分层设计原则。
内容的提问来源于stack exchange,提问作者momongarZ
相关产品推荐
相关产品推荐

