Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Navigation inside Nested Future

Tags:

flutter

dart

Edit: Problem solved exactly as I want in this new question topic:

Conditional Navigation inside Widget Tree

Old Question:

This is my Boot Screen and I want to create conditional Navigations but as I understand FutureBuilder does not have logic for Navigation.

This is my Boot Screen build method:

@override
Widget build(BuildContext context) {
  return Material(
    child: ScopedModelDescendant<MainModel>(
      builder: (BuildContext context, Widget child, MainModel model) {
        return FutureBuilder(
          future: model.bootUp(),
          builder: (context, bootSnapshot) {
            print('====${bootSnapshot.data} is SNAPSHOT DATA====');
            return !bootSnapshot.hasData
                ? _buildSplash(context)
                : bootSnapshot.data
                    ? FutureBuilder(
                        future: model.fetchAll(model.tempUser),
                        builder: (context, dataSnapshot) {
                          return !dataSnapshot.hasData
                              ? _buildSplash(context)
                              : Navigator.of(context).pushReplacement(
                                  MaterialPageRoute(
                                      builder: (context) => HomePage()),
                                );
                        })
                    : Navigator.of(context).pushReplacement(
                        MaterialPageRoute(
                          builder: (context) => FirstScreen(),
                        ),
                      );
          },
        );
      },
    ),
  );
}

As you see in the code, first I check up is user login before or not with an async method, then if he is login before, then I'm fetching the data related to him, once the fetching completed I want to navigate into the User Home page.

The error log:

I/flutter (24348): ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
I/flutter (24348): The following assertion was thrown building FutureBuilder<String>(dirty, state:
I/flutter (24348): _FutureBuilderState<String>#e0594):
I/flutter (24348): setState() or markNeedsBuild() called during build.
I/flutter (24348): This Overlay widget cannot be marked as needing to build because the framework is already in the
I/flutter (24348): process of building widgets. A widget can be marked as needing to be built during the build phase
I/flutter (24348): only if one of its ancestors is currently building. This exception is allowed because the framework
I/flutter (24348): builds parent widgets before children, which means a dirty descendant will always be built.
I/flutter (24348): Otherwise, the framework might not visit this widget during this build phase.
I/flutter (24348): The widget on which setState() or markNeedsBuild() was called was:
I/flutter (24348):   Overlay-[LabeledGlobalKey<OverlayState>#c7eb6](state: OverlayState#953bd(entries:
I/flutter (24348):   [OverlayEntry#b9486(opaque: false; maintainState: false), OverlayEntry#af059(opaque: false;
I/flutter (24348):   maintainState: true), OverlayEntry#81d00(opaque: false; maintainState: false),
I/flutter (24348):   OverlayEntry#be7c4(opaque: false; maintainState: true)]))
I/flutter (24348): The widget which was currently being built when the offending call was made was:
I/flutter (24348):   FutureBuilder<String>(dirty, state: _FutureBuilderState<String>#e0594)
I/flutter (24348):
I/flutter (24348): When the exception was thrown, this was the stack:
I/flutter (24348): #0      Element.markNeedsBuild.<anonymous closure> (package:flutter/src/widgets/framework.dart:3485:11)
I/flutter (24348): #1      Element.markNeedsBuild (package:flutter/src/widgets/framework.dart:3511:6)
I/flutter (24348): #2      State.setState (package:flutter/src/widgets/framework.dart:1146:14)
I/flutter (24348): #3      OverlayState.insertAll (package:flutter/src/widgets/overlay.dart:301:5)
I/flutter (24348): #4      OverlayRoute.install (package:flutter/src/widgets/routes.dart:43:24)
I/flutter (24348): #5      TransitionRoute.install (package:flutter/src/widgets/routes.dart:185:11)
I/flutter (24348): #6      ModalRoute.install (package:flutter/src/widgets/routes.dart:861:11)
I/flutter (24348): #7      NavigatorState.pushReplacement (package:flutter/src/widgets/navigator.dart:1618:14)
I/flutter (24348): #8      BootScreen.build.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:mostadam/pages/boot_screen.dart:49:49)
I/flutter (24348): #9      _FutureBuilderState.build (package:flutter/src/widgets/async.dart)
I/flutter (24348): #10     StatefulElement.build (package:flutter/src/widgets/framework.dart:3809:27)
I/flutter (24348): #11     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3721:15)
I/flutter (24348): #12     Element.rebuild (package:flutter/src/widgets/framework.dart:3547:5)
I/flutter (24348): #13     BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2286:33)
I/flutter (24348): #14     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding&PaintingBinding&SemanticsBinding&RendererBinding&WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:676:20)
I/flutter (24348): #15     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding&PaintingBinding&SemanticsBinding&RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:219:5)
I/flutter (24348): #16     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:990:15)
I/flutter (24348): #17     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:930:9)
I/flutter (24348): #18     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:842:5)
I/flutter (24348): #19     _invoke (dart:ui/hooks.dart:154:13)
I/flutter (24348): #20     _drawFrame (dart:ui/hooks.dart:143:3)
like image 802
Esen Mehmet Avatar asked Feb 14 '19 13:02

Esen Mehmet


1 Answers

Edit: The answer down below very old. The real solution is using WidgetsBinding. Within snapshot.hasData condition, put this method:

    WidgetsBinding.instance!.addPostFrameCallback((_) {
      Navigator.of(context)
          .pushReplacement(MaterialPageRoute(builder: (context) {
        if (~snapshot condition~) {
          return HomePage();
        }
        return FirstPage();
      }));
    });

addPostFrameCallback is a method that executed once right after build method execution completes.

Anmol has answered the question on the comments.

The solution is easy, just return the page you want to navigate. But for some rare specific situations, it's not enough IMO. I hope we have better options for future updates.

Solution:

instead of

Navigator.of(context).pushReplacement( MaterialPageRoute( builder: (context) => HomePage();

simply put:

return HomePage();

same for:

return FirstScreen();
like image 184
Esen Mehmet Avatar answered Oct 10 '22 07:10

Esen Mehmet