Arun-
Arun-

Reputation: 865

Flutter : Navigator operation requested with a context that does not include a Navigator

I have a scenario wherein I check the value of SharePreferences based on the value it will redirect the user to HomePage or LandingPage. I am not sure where did I got wrong? but I am getting this error below: I guess its not getting the context right any idea how do I get it?.

Unhandled Exception: Navigator operation requested with a context that does not include a Navigator. E/flutter (11533): 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.

Here is my code:

import 'package:credit/src/pages/landing.dart';
import 'package:flutter/material.dart';
import 'package:credit/src/pages/credit/home.dart';
import 'package:shared_preferences/shared_preferences.dart';

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  MyApp({Key key}) : super(key: key);

  _LoadingPageState createState() => _LoadingPageState();
}

class _LoadingPageState extends State<MyApp> {
  @override
  void initState() {
    super.initState();
    getUserStatus().then((userStatus) {
      if (userStatus == null) {
        Navigator.of(context)
            .push(MaterialPageRoute<Null>(builder: (BuildContext context) {
          return LandingPage();
        }));
      } else {
        Navigator.of(context)
            .push(MaterialPageRoute<Null>(builder: (BuildContext context) {
          return HomePage();
        }));
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Container(
        child: Center(
      child: CircularProgressIndicator(),
    ));
  }
}

Future<String> getUserStatus() async {
  SharedPreferences prefs = await SharedPreferences.getInstance();
  String userStatus = prefs.getString('userstatus');
  print("==On Load Check ==");
  print(userStatus);
  return userStatus;
}

Upvotes: 1

Views: 8153

Answers (2)

raghu
raghu

Reputation: 841

I have changed my code from

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Demo App',
      theme: ThemeData(
        primarySwatch: white,
        scaffoldBackgroundColor: Colors.white,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: Text('Demo App'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              ElevatedButton(
                  onPressed: () {
                    Navigator.push(
                        context,
                        MaterialPageRoute(
                            builder: (context) =>
                                HomeScreen(title: 'Demo Home')));
                  },
                  child: Text('Open Home Screen'))
            ],
          ),
        ),
      ),
    );
  }
 

To

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Demo App',
        theme: ThemeData(
          primarySwatch: white,
          scaffoldBackgroundColor: Colors.white,
        ),
        home: InitScreen());
  }
}

class InitScreen extends StatelessWidget {
  const InitScreen({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Demo App'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
                onPressed: () {
                  Navigator.push(
                      context,
                      MaterialPageRoute(
                          builder: (context) =>
                              HomeScreen(title: 'Demo Home')));
                },
                child: Text('Open Home Screen'))
          ],
        ),
      ),
    );
  }

What changed?

Create a separate widget for home code in MyApp with InitScreen

What was the issue?

When we try to push Route by using Navigator.of(context), flutter will try to find Navigator in the widget tree of the given context. In the initial code, there was no widget that has Navigator. So, create a separate widget for home code. And the MaterialApp widget in MyApp will have Navigator.

Upvotes: 1

Mikhail Ponkin
Mikhail Ponkin

Reputation: 2711

When you call Navigator.of(context) framework goes up in widget tree attached to provided context and tries to find the closest Navigator.

The widget tree you showed does not have one, so you need to include Navigator in the widget tree.
Easiest option is to use MaterialApp with your widget passed as home. MaterialApp is creating navigator inside itself. (CupertinoApp does it too)

Updated code from original example:

import 'package:credit/src/pages/landing.dart';
import 'package:flutter/material.dart';
import 'package:credit/src/pages/credit/home.dart';
import 'package:shared_preferences/shared_preferences.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  MyApp({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: LoadingPage(),
    );
  }
}

class LoadingPage extends StatefulWidget {
  LoadingPage({Key key}) : super(key: key);

  _LoadingPageState createState() => _LoadingPageState();
}

class _LoadingPageState extends State<LoadingPage> { // note type update
  @override
  void initState() {
    super.initState();
    getUserStatus().then((userStatus) {
      if (userStatus == null) {
        Navigator.of(context)
            .push(MaterialPageRoute<Null>(builder: (BuildContext context) {
          return LandingPage();
        }));
      } else {
        Navigator.of(context)
            .push(MaterialPageRoute<Null>(builder: (BuildContext context) {
          return HomePage();
        }));
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Container(
        child: Center(
      child: CircularProgressIndicator(),
    ));
  }
}

Future<String> getUserStatus() async {
  SharedPreferences prefs = await SharedPreferences.getInstance();
  String userStatus = prefs.getString('userstatus');
  print("==On Load Check ==");
  print(userStatus);
  return userStatus;
}

Upvotes: 1

Related Questions