1

I've looked over several other posts with this same error about the Navigator and either their code looks different, it fails in totally different places, or other reasons and I must be missing something important. Where this fails for me is only from resuming from background or sleep. The app lifecycle detects "resume" and I want to navigate to the login page for the user to select a profile or login. The error below shows any way I try to use a Navigator in that function didChangeAppLifecycleState(AppLifecycleState state). Actually if I use Navigator anywhere in main.dart it gives the error. Outside of main.dart Navigator works great.

Navigator operation requested with a context that does not include a Navigator.
The context used to push or pop routes from the Navigator must be that of a widget that is a descendant of a Navigator widget.

The code that causes the error in main.dart :

@override
void didChangeAppLifecycleState(AppLifecycleState state) {
    super.didChangeAppLifecycleState(state);
    print("State changed! ${state}");
    setState(() {
        _notification = state;
    });
    if(state == AppLifecycleState.resumed){
        NavService().navigateTo(context, '/login');
    }
}

The main.dart build looks like this:

@override
Widget build(BuildContext context) {
    return 
    MaterialApp(
    theme: new ThemeData(
        primarySwatch: themeSwatchColor,
        brightness: Brightness.light,
        primaryColor: themePrimaryColor,
        accentColor: themeAccentColor,
    ),
    initialRoute: '/',
    navigatorObservers: <NavigatorObserver>[
        NavService(), // this will listen all changes
        
    ],
    onGenerateRoute: (routeSettings) {
        switch (routeSettings.name) {
            case '/':
                return MaterialPageRoute(builder: (_) => LoginPage());
            case '/login':
                return MaterialPageRoute(builder: (_) => LoginPage());
            case '/home':
                return MaterialPageRoute(builder: (_) => HomePage());
            case '/items':
                return MaterialPageRoute(builder: (_) => ItemLookupPage());
            case '/settings':
                return MaterialPageRoute(builder: (_) => SettingsPage());
            case '/oldsettings':
                return MaterialPageRoute(builder: (_) => SecondPage());
            case '/pickorders':
                return MaterialPageRoute(builder: (_) => ReceivedOrdersPage());
            case '/orders':
                return MaterialPageRoute(builder: (_) => OrdersPage());
            case '/receiving':
                return MaterialPageRoute(builder: (_) => ReceivingPage());
            case '/inventory':
                return MaterialPageRoute(builder: (_) => InventoryPage());
            default:
                return MaterialPageRoute(builder: (_) => LoginPage());
        }
    },

    home: (noAccount == true)
        ? LoginPage()
        : HomePage(),
    );
}

NavService.dart:

class NavService extends RouteObserver {

    void saveLastRoute(String lastRoute) async {
        if(lastRoute != "/login" && lastRoute != "/error"){
            final SharedPreferences prefs = await SharedPreferences.getInstance();
            prefs.setString('last_route', lastRoute);
        }
    }

    Future<dynamic> navigateTo(BuildContext context, String routeName, {Map data}) async {
        saveLastRoute(routeName);
        return Navigator.pushNamed(context, routeName,  arguments: data);
    }
}

I also tried skipping my NavService and used Navigator directly, but the same error shows.

Navigator.of(context).push(
    MaterialPageRoute(
        builder: (context) => LoginPage(),
    ),
);

I tried using a GlobalKey as other posts have suggested, but the NavService() using the RouteObserver breaks when I do that.

The NavService and page routing works very well anywhere in the app. Its only while navigating in main.dart I'm having the issue. I just noticed if I place the above Navigator.of().push in initState() I get the same error. Maybe my MaterialApp is setup wrong? Or am I using the NavService incorrectly?

Thanks for any help!

gregthegeek
  • 1,353
  • 3
  • 14
  • 24

1 Answers1

3

The didChangeAppLifecycleState method does not provide any context unlike the build method. You would have to navigate without using context by setting a global key for your navigation:

final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();

Pass it to MaterialApp:

    MaterialApp(
      title: 'MyApp',
      onGenerateRoute: generateRoute,
      navigatorKey: navigatorKey,
    );

Push routes:

navigatorKey.currentState.pushNamed('/someRoute');

Credits to this answer

CoderUni
  • 5,474
  • 7
  • 26
  • 58
  • 2
    Thanks so much! I think when I tried using navigatorKey I had it in my NavService(). I just added it only to MyAPP() in main.dart and it worked perfectly. NavService() works normally everywhere else. Ugh. Sometimes its just that one little difference you don't catch and you need s second set of eyes to point out something new. Thanks again! – gregthegeek Nov 07 '20 at 02:35