Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

InheritedWidget - The getter was called on null after navigator.push

I'm having trouble trying to access an InheritedWidget after navigating to a new widget.

I have my top level widget like this

class App extends StatelessWidget{
  build(context){
    return MaterialApp(
        title: 'Iniciar Sesion',
        home: LoginBlocProvider(child: WelcomeScreen()),
    );
  }  
}

Then WelcomeScreen has a button to navigate to LoginScreen

class WelcomeScreen extends StatelessWidget {

  @override Widget build(BuildContext context){
    return Scaffold(
      body: Center(child: MyButton)
    );
  }
}

class MyButton extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return RaisedButton(
      shape: StadiumBorder(),
      child: Text('Ingresar', style: TextStyle(color: Colors.black)),
      elevation: 5.0,
      onPressed: () { 
        Navigator.of(context).push(MaterialPageRoute(
           builder: (BuildContext context) =>LoginScreen()
        ));
      }
    );
  }
}

Finally in LoginScreen I want to access the InheritedWidget

class LoginScreen extends StatefulWidget {
  @override
  _LoginScreenState createState() => _LoginScreenState();
}

class _LoginScreenState extends State<LoginScreen> {
  LoginBloc bloc;  

  @override void didChangeDependencies() {
    bloc = LoginBlocProvider.of(context);
    super.didChangeDependencies();
  }

  @override Widget build(BuildContext context){
    return Scaffold(
      body:
      Stack(
        fit: StackFit.expand,
        children: <Widget>[
          Positioned(
            top: 0.0,
            child: Image.asset('assets/images/img.jpg',
              fit: BoxFit.none,
            ),
          ),
          _buildLogin(),
        ],
      ),
    );
  }
}

Edited: Here it's the LoginBlocProvider

class LoginBlocProvider extends InheritedWidget {
  final bloc;

  LoginBlocProvider({Key key, Widget child}) 
  : bloc = LoginBloc(), 
  super(key:key, child:child);

  @override
  bool updateShouldNotify(InheritedWidget oldWidget) => true;

  static LoginBloc of(BuildContext context) {
    return (context.inheritFromWidgetOfExactType(LoginBlocProvider) as LoginBlocProvider).bloc;
  }
}

But, when I run the .of method of the InheritedWidget I get this error

I/flutter (27725): The following NoSuchMethodError was thrown building Builder:
I/flutter (27725): The getter 'bloc' was called on null.
I/flutter (27725): Receiver: null
I/flutter (27725): Tried calling: bloc

I have the impression that it all has to do with the context in the Navigator.push builder method. Because if I use the LoginScreen widget without the Navigator.push, I can use the InheritedWidget perfectly fine

The error is happening because the context passed to the LoginBlocProvider.of() method is not finding the instance.

Any thoughts on this?

like image 977
Sebastian Avatar asked Sep 10 '18 17:09

Sebastian


2 Answers

In the code you've provided, LoginScreen is not a descendant of LoginBlocProvider which is why it can't find the ancestor widget. Your code wraps the WelcomeScreen route in LoginBlocProvider, but not the whole navigator. The solution is to wrap your MaterialApp in LoginBlocProvider and then you will have access to it everywhere in your app.

class App extends StatelessWidget {
  @override
  Widget build(context) {
    return LoginBlocProvider(
      child: MaterialApp(
        title: 'Iniciar Sesion',
        home: WelcomeScreen(),
      ),
    );
  }
}
like image 82
Kirollos Morkos Avatar answered Nov 01 '22 17:11

Kirollos Morkos


InheritedWidget should wrap the full MatrialApp widget (root widget)

like image 28
MSaudi Avatar answered Nov 01 '22 17:11

MSaudi