How to solve: Flutter [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: type 'Null' is not a subtype of type 'BuildContext'

Question

Asked by C K on January 01, 2022 (source).

I'm trying to validate the input data entered by the user for signing up and getting this error [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: type 'Null' is not a subtype of type 'BuildContext'

Here is my code:

class _LoginState extends State<Login> {
  final AuthService _auth = AuthService();
  final _formKey = GlobalKey<FormState>();

  TextEditingController _emailController = TextEditingController();
  TextEditingController _passwordController = TextEditingController();

  GoogleSignIn _googleSignIn = GoogleSignIn(scopes: ['email']);
  late String _email, _password;
  String error = "";

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

  bool _isObscure = true;
  @override
  Widget build(BuildContext context) {
    MediaQueryData mediaQueryData = MediaQuery.of(context);
    GoogleSignInAccount? user = _googleSignIn.currentUser;
    final isKeyboard = MediaQuery.of(context).viewInsets.bottom != 0;
    return Scaffold(
      resizeToAvoidBottomInset: false,
      appBar: !isKeyboard
          ? AppBar(
          titleSpacing: 12,
          leading: ModalRoute.of(context)?.canPop == true
              ? IconButton(
                  splashColor: Colors.transparent,
                  padding: const EdgeInsets.only(left: 30.0, bottom: 15.0),
                  icon: Icon(
                    Icons.arrow_back,
                    size: 35,
                  ),
                  onPressed: () => Navigator.of(context).pop(),
                  color: Colors.black,
                )
              : null,
          title: Image.asset('images/logo-name.png'),
          backgroundColor: new Color(0xffff),
          shadowColor: Colors.transparent,
          elevation: 0,
          toolbarHeight: 90.0,
        )
      : null,
  body: Center(
    child: Column(
      children: <Widget>[
        if (!isKeyboard)
          Container(
            child: RichText(
              textAlign: TextAlign.center,
              text: TextSpan(
                  text: "Made e-Groceries easier",
                  style: TextStyle(
                      fontSize: mediaQueryData.textScaleFactor /
                          mediaQueryData.textScaleFactor *
                          33,
                      fontFamily: 'Inter',
                      fontWeight: FontWeight.w600,
                      color: Colors.black)),
            ),
            width: mediaQueryData.size.width * 0.8,
          ),

        Container(
          child: Image(
              image: AssetImage("images/login.png"), fit: BoxFit.contain),
        ),

        Container(
            width: mediaQueryData.size.width * 0.85,
            child: Form(
                key: _formKey,
                child: SingleChildScrollView(
                    child: Column(
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: [
                      TextFormField(
                          controller: _emailController,
                          validator: (input) {
                            if (input!.isEmpty)
                              return 'Pleas enter a valid Email';
                          },
                          decoration: InputDecoration(
                            focusedErrorBorder: OutlineInputBorder(
                              borderSide: BorderSide(color: Colors.red),
                            ),
                            errorBorder: OutlineInputBorder(
                              borderSide: BorderSide(color: Colors.red),
                            ),
                            errorStyle: TextStyle(height: 0.4),
                            contentPadding:
                                const EdgeInsets.symmetric(vertical: 20.0),
                            enabledBorder: OutlineInputBorder(
                                borderSide:
                                    BorderSide(color: Color(0xff2C6846))),
                            focusColor: Color(0xff2C6846),
                            focusedBorder: OutlineInputBorder(
                                borderSide: BorderSide(
                              color: Color(0xff2C6846),
                            )),
                            labelStyle: TextStyle(color: Color(0xff2C6846)),
                            labelText: "Email",
                            prefixIcon:
                                Icon(Icons.mail, color: Color(0xff2C6846)),
                          ),
                          onSaved: (input) => _email = input!),
                      SizedBox(height: 20),
                      TextFormField(
                          obscureText: _isObscure,
                          enableSuggestions: false,
                          autocorrect: false,
                          controller: _passwordController,
                          validator: (input) {
                            if (input!.length < 6)
                              return 'Provide minimum 6 character';
                          },
                          decoration: InputDecoration(
                              focusedErrorBorder: OutlineInputBorder(
                                borderSide: BorderSide(color: Colors.red),
                              ),
                              errorBorder: OutlineInputBorder(
                                borderSide: BorderSide(color: Colors.red),
                              ),
                              errorStyle: TextStyle(height: 0.4),
                              contentPadding: const EdgeInsets.symmetric(
                                  vertical: 20.0),
                              enabledBorder: OutlineInputBorder(
                                  borderSide:
                                      BorderSide(color: Color(0xff2C6846))),
                              focusColor: Color(0xff2C6846),
                              focusedBorder: OutlineInputBorder(
                                  borderSide:
                                      BorderSide(color: Color(0xff2C6846))),
                              labelStyle:
                                  TextStyle(color: Color(0xff2C6846)),
                              labelText: "Password",
                              suffixIcon: IconButton(
                                icon: Icon(
                                  _isObscure
                                      ? Icons.visibility
                                      : Icons.visibility_off,
                                  color: Color(0xff2C6846),
                                ),
                                onPressed: () {
                                  setState(() {
                                    _isObscure = !_isObscure;
                                  });
                                },
                              ),
                              prefixIcon: Icon(Icons.lock,
                                  color: Color(0xff2C6846))),
                          onSaved: (input) => _password = input!),
                    ])))),
        SizedBox(height: 20),
        ButtonTheme(
          buttonColor: Color(0xff2C6846),
          minWidth: mediaQueryData.size.width * 0.85,
          height: 60.0,
          child: RaisedButton(
              shape: RoundedRectangleBorder(
                borderRadius: new BorderRadius.circular(5.0),
              ),
              padding: EdgeInsets.fromLTRB(70, 10, 70, 10),
              onPressed: () {
                if (_formKey.currentState!.validate()) {
                  signInUser();
                }
              },
              child: Text('Log In',
                  style: TextStyle(
                      color: Colors.white,
                      fontSize: 20.0,
                      fontWeight: FontWeight.w600))),
        )
      ],
    ),
  ),
);
}

  void signInUser() async {
    dynamic authResult = await _auth.loginUser(
        _emailController.text, _passwordController.text);
    if (authResult == null) {
      print("Sign in error. Could not be able to login");
    } else {
      _emailController.clear();
      _passwordController.clear();
      print('Sign in Successful');
      Navigator.push(
          context, MaterialPageRoute(builder: (context) => HomePage()));
    }
  }
}

The above code is for AuthService.dart:

class AuthService {
  final FirebaseAuth _auth = FirebaseAuth.instance;

  showError(Object errormessage) {
    var context;
    showDialog(
        context: context,
        builder: (BuildContext context) {
          return AlertDialog(
            title: Text('Note'),
            content: Text(errormessage.toString()),
            actions: <Widget>[
              FlatButton(
                  onPressed: () {
                    Navigator.of(context).pop();
                  },
                  child: Text('OK'))
            ],
          );
        });
  }

  Future loginUser(String email, String password) async {
    try {
      UserCredential result = await _auth.signInWithEmailAndPassword(
          email: email.toString(), password: password.toString());
      return result.user;
    } catch (e) {
      showError(e);
    }
  }
}

Ignore the messy indentation as this is my first time using stack overflow.

Answer

Question answered by h8moss (source).

...
showError(Object errormessage) {
    var context;
    showDialog(
        context: context,
...

the showDialog method takes a context parameter, it uses this context to find some special useful information about your application in order to properly show the dialog, you are not passing a proper context.

What you are doing is first declaring a variable context and then passing that, the variable's value is null by default, so you get an error.

To fix this, you need to pass the real context used by your app:

...
showError(BuildContext context, Object errormessage) {
    showDialog(
        context: context,
...

and then:

Future loginUser(BuildContext context, String email, String password) async {
    try {
      UserCredential result = await _auth.signInWithEmailAndPassword(
          email: email.toString(), password: password.toString());
      return result.user;
    } catch (e) {
      showError(context, e);
    }
  }

And finally:

...
void signInUser() async {
    dynamic authResult = await _auth.loginUser(context, _emailController.text, _passwordController.text);
...
FLUTTER FLUTTER-LAYOUT FLUTTER-WEB
SHARE: