So, I started to make a Flutter App with sdk: ">=2.16.2 <3.0.0" and Firebase Integration. I have the following code on main.dart for "authStateChanges()":
if (snapshot.connectionState == ConnectionState.done) {
FirebaseAuth.instance.authStateChanges().listen((User? user) {
if (user == null) {
Navigator.of(context).pushReplacementNamed('login');
} else {
Navigator.of(context).pushReplacementNamed('home');
}
});
}
It works at the first time when loading the app, but If the user signs in (or out), then the "Unhandled Exception: Null check operator used on a null value" occurs on Navigator.
Here is the full main.dart code:
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:pollux_android/src/pages/error_page.dart';
import 'package:pollux_android/src/pages/loading_page.dart';
import 'package:pollux_android/src/routes/routes.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
MyApp({Key? key}) : super(key: key);
@override
State<MyApp> createState() => _MyAppState();
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
}
class _MyAppState extends State<MyApp> {
final Future<FirebaseApp> _initialization = Firebase.initializeApp();
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
routes: polluxRoutes,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: mainScreen(),
);
}
mainScreen() {
return FutureBuilder(
future: _initialization,
builder: (context, snapshot) {
if (snapshot.hasError) {
return const ErrorPage(
errorMessage: 'Unknown error',
);
}
if (snapshot.connectionState == ConnectionState.done) {
FirebaseAuth.instance.authStateChanges().listen((User? user) {
if (user == null) {
Navigator.of(context).pushReplacementNamed('login');
} else {
Navigator.of(context).pushReplacementNamed('home');
}
});
}
return const LoadingPage();
},
);
}
}
I don't get why it fails to Navigate the second time on authStateChanges(). I appreciate for the help you can provide. I believe it has to do with the Null check on newer versions as this issue didn't happen on sdk 2.7.0
CodePudding user response:
Split your file main.dart
into two different files
Do not put any logic in this file main.dart
Split file is solution for your issue
main.dart
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
MyApp({Key? key}) : super(key: key);
@override
State<MyApp> createState() => _MyAppState();
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
}
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
routes: {
'home': (_) => HomeScreen(),
},
home: LoginScreen(),
);
}
}
login_screen.dart
import 'package:flutter/material.dart';
class LoginScreen extends StatefulWidget {
const LoginScreen({Key? key}) : super(key: key);
@override
State<LoginScreen> createState() => _SplashScreenState();
}
class _SplashScreenState extends State<LoginScreen> {
final Future<FirebaseApp> _initialization = Firebase.initializeApp();
@override
Widget build(BuildContext context) {
return mainScreen();
}
mainScreen() {
return FutureBuilder(
future: _initialization,
builder: (context, snapshot) {
if (snapshot.hasError) {
return const ErrorPage(
errorMessage: 'Unknown error',
);
}
if (snapshot.connectionState == ConnectionState.done) {
FirebaseAuth.instance.authStateChanges().listen((User? user) {
if (user == null) {
Navigator.of(context).pushReplacementNamed('login');
} else {
Navigator.of(context).pushReplacementNamed('home');
}
});
}
return const LoadingPage();
},
);
}
}
CodePudding user response:
For some reason the context becomes null when authStateChanges() happens. Thanks to @Saitoh-Akira, I got the idea of using navigator Key and use it to navigate without the context. If I understand this correctly, the Navigator needs a state. Anyway, adding the navigator Key and use it worked good:
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:pollux_android/src/pages/error_page.dart';
import 'package:pollux_android/src/pages/loading_page.dart';
import 'package:pollux_android/src/routes/routes.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
MyApp({Key? key}) : super(key: key);
@override
State<MyApp> createState() => _MyAppState();
// final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
}
class _MyAppState extends State<MyApp> {
final Future<FirebaseApp> _initialization = Firebase.initializeApp();
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
routes: polluxRoutes,
navigatorKey: navigatorKey,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: mainScreen(),
);
}
mainScreen() {
return FutureBuilder(
future: _initialization,
builder: (context, snapshot) {
if (snapshot.hasError) {
return const ErrorPage(
errorMessage: 'Some unknown error happened',
);
}
if (snapshot.connectionState == ConnectionState.done) {
FirebaseAuth.instance.authStateChanges().listen((User? user) {
if (user == null) {
navigatorKey.currentState?.pushNamedAndRemoveUntil('login', (route) => false);
} else {
navigatorKey.currentState?.pushNamedAndRemoveUntil('home', (route) => false);
}
});
}
return const LoadingPage();
},
);
}
}