You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter:基于多状态变量显示Overlay功能失效问题求助

Flutter Riverpod状态管理与页面切换异常

场景说明

我有一个名为TestMain的Flutter页面,使用白色背景的Scaffold,页面body需要根据三个布尔状态切换显示内容:

  • isLocked、isPaused:由Riverpod Stream Provider触发更新,通过StateProvider实现全局访问
  • isCheating:由AppLifecycle事件触发,同样通过StateProvider实现全局访问

Provider定义

final isCheatingProvider = StateProvider.autoDispose<bool>((ref) => false);

isPausedProvider和isLockedProvider的定义与上述代码完全一致

完整页面代码

class TestMain extends ConsumerStatefulWidget {
  const TestMain({super.key});

  @override
  ConsumerState<TestMain> createState() => _TestMainScreenState();
}

class _TestMainScreenState extends ConsumerState<TestMain>
    with WidgetsBindingObserver {
  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) async {
    super.didChangeAppLifecycleState(state);

    final isCheating = ref.watch(isCheatingProvider.notifier);

    switch (state) {
      case AppLifecycleState.resumed:
      case AppLifecycleState.inactive:
        await sendCheatingAttempt(ref);
        setState(() {
          isCheating.state = true;
        });
        break;
      case AppLifecycleState.paused:
        await sendCheatingAttempt(ref);
        setState(() {
          isCheating.state = true;
        });
        break;
      case AppLifecycleState.detached:
        await sendCheatingAttempt(ref);
        setState(() {
          isCheating.state = true;
        });
        break;
    }
  }

  @override
  Widget build(BuildContext context) {
    final List<Item> items = ref.watch(itemsProvider);
    final AsyncValue<dynamic> wsTestListenerMessage =
        ref.watch(testListenerProvider);

    final isLocked = ref.watch(isLockedProvider.notifier);
    final isPaused = ref.watch(isPausedProvider.notifier);
    final isCheating = ref.watch(isCheatingProvider.notifier);

    wsTestListenerMessage.when(
      loading: () => {},
      error: (err, stack) => print('Test State Error: $err'),
      data: (message) async {
        Future.delayed(const Duration(seconds: 0), () {
          if (message["lock"] == true) {
            isLocked.state = true;
          }
          if (message["unlock"] == true) {
            isLocked.state = false;
          }
          if (message["paused"] == true) {
            isPaused.state = true;
          }
          if (message["resumed"] == true) {
            isPaused.state = false;
          }
        });
      },
    );

    return Scaffold(
      backgroundColor: Colors.white,
      body: SafeArea(
          child: isPaused.state
              ? const ErrorOverlay(text: 'paused')
              : isLocked.state || isCheating.state
                  ? const ErrorOverlay(text: 'cheating')
                  : const TestView()),
    );
  }
}

ErrorOverlay为自定义组件,作用是居中显示红色大文本

问题点

  1. 整体功能始终无法正常工作
  2. 为避免在build方法中修改Provider触发报错,用Future.delayed(const Duration(seconds: 0), () {})包裹状态更新逻辑,但未解决问题
  3. 在didChangeAppLifecycleState中通过setState修改isCheating状态,但监听器中使用setState会导致重复调用,进而让Overlay重复显示

内容的提问来源于stack exchange,提问作者Jasper

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 07:15:32