【问题标题】:Navigate while Widget state build is being executed在执行 Widget 状态构建时导航
【发布时间】:2019-12-05 15:26:28
【问题描述】:

我正在构建一个简单的 Flutter 应用。它的启动屏幕确定用户是否已登录,并根据此重定向到登录或主/主屏幕。

我的启动屏幕是StatefulWidget,它的状态如下图所示。它使用扩展 ChangeNotifier 的 ViewModel 类(它的代码无关紧要,所以我没有包含它)。

class _LaunchPageState extends State<LaunchPage> {
          LaunchViewModel _viewModel = LaunchViewModel();

          @override
          void initState() {
            super.initState();
            _viewModel.checkSessionStatus();
          }

          @override
          Widget build(BuildContext context) {
            return ChangeNotifierProvider<LaunchViewModel>(
              builder: (_) => _viewModel,
              child: Scaffold(
                body: Consumer<LaunchViewModel>(
                  builder: (context, viewModel, _) {
                    if (viewModel.state is LaunchInitial) {
                      return CircularProgressIndicator();
                    }
                    if (viewModel.state is LaunchLoginPage) {
                      Navigator.pushNamed(context, "login");
                    }
                    if (viewModel.state is LaunchMainPage) {
                      Navigator.pushNamed(context, "main");
                    }
                    return Container();
                  },
                ),
              ),
            );
          }
        }

ViewModel 发出 3 种状态之一:

  • LaunchInitial:默认状态。
  • LaunchLoginPage:表示应该显示登录页面。
  • LaunchMainPage:表示应该显示主页。

LaunchInitial 状态处理得很好,屏幕上会显示一个进度条。但是其他 2 个状态会导致应用程序崩溃。抛出以下错误:

This Overlay widget cannot be marked as needing to build because the framework is already in the process of building widgets

似乎在执行消费者的build 方法时尝试重定向到另一个屏幕会导致此问题。这样做的正确方法是什么?

谢谢!

【问题讨论】:

    标签: flutter flutter-navigation flutter-provider


    【解决方案1】:

    您不能在小部件树中直接调用Navigator。如果您有event-state builder,那么最好更改您正在呈现的小部件树:

    builder: (context, viewModel, _) {
                        if (viewModel.state is LaunchInitial) {
                          return CircularProgressIndicator();
                        }
                        if (viewModel.state is LaunchLoginPage) {
                          return LoginPage();
                        }
                        if (viewModel.state is LaunchMainPage) {
                          return MainPage();
                        }
                        return Container();
                      },
    

    您必须在build 方法中返回Widget

    或者,您也可以使用Navigation

      @override
      void didChangeDependencies() {
        WidgetsBinding.instance.addPostFrameCallback((_) {
          if (viewModel.state is LaunchLoginPage) {
            Navigator.pushNamed(context, "login");
          }
          if (viewModel.state is LaunchMainPage) {
            Navigator.pushNamed(context, "main");
          }
        });
        super.didChangeDependencies();
      }
    

    addPostFrameCallback 方法将在build 方法完成后立即调用,您可以在其中导航。

    确保您的provider 没有lifecycle 问题。

    【讨论】:

    • 但是我想离开启动屏幕并转到登录或主屏幕,而不是仅仅替换启动屏幕的内容。
    • 啊,所以导航是在构建小部件之后发生的,这似乎是一个好方法。谢谢!
    • 在后帧回调中返回进度小部件是没有用的,应该删除。这必须在 build() 方法中代替(并且不需要任何限定)。
    • @Ber 你是对的。感谢您的提醒,可能我直接复制粘贴了代码,无论如何它具有误导性。
    猜你喜欢
    • 2020-05-31
    • 1970-01-01
    • 2020-10-01
    • 1970-01-01
    • 2023-01-17
    • 1970-01-01
    • 2019-04-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多