I am new to flutter and this is my first project. I have writter a basic app that uses firebase to login, register, verify emails, and has an as of now empty home page. The code runs fine but i have a warning in two places. In these lines of code Navigator.of(context).pushNamedAndRemoveUntil(loginRoute, (_) => false,);
and this Navigator.of(context).pushNamedAndRemoveUntil(mainRoute, (route) => false,);
i get this warning: Don't use 'BuildContext's across async gaps. Try rewriting the code to not use the 'BuildContext', or guard the use with a 'mounted' check.
I know that using navigator and pushing is not the most optimal technique but as i said it is my first project and this is the most eazy way. I tried using if(!mounted)return;
but it didn’t work. My app runs fine and does not have any problems but as i saw this warning can cause problems in specific senarios so i want to know how to fix it in case i encounter it again. This is the code of the main file only. I also have files for the login and register that i don’t think are important.
import 'package:project/constants/routes.dart';
import 'package:project/firebase_options.dart';
import 'package:project/views/loginview.dart';
import 'package:project/views/registerview.dart';
import 'package:project/views/verifyview.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'dart:developer' as devtools show log;
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: const Color.fromARGB(255, 58, 133, 183)),
useMaterial3: true,
),
home: const HomePage(),
routes: {
loginRoute: (context) => const LoginView(),
registerRoute:(context) => const RegisterView(),
mainRoute:(context) => const NotesView()
},
),
);
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
),
builder:(context, snapshot) {
switch (snapshot.connectionState){
case ConnectionState.done:
final user = FirebaseAuth.instance.currentUser;
if(user != null)
{
if(user.emailVerified)
{
return const NotesView();
}
else
{
return const VerifyEmailView();
}
}
else
{
return const LoginView();
}
default:
return const CircularProgressIndicator();
}
},
);
}
}
enum MenuAction { logout }
class NotesView extends StatefulWidget {
const NotesView({super.key});
@override
State<NotesView> createState() => _NotesViewState();
}
class _NotesViewState extends State<NotesView> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("My notes"),
actions: [
PopupMenuButton<MenuAction>(
onSelected: (value) async {
switch (value) {
case MenuAction.logout:
final shouldLogOut = await showLogOutDialog(context);
if(shouldLogOut)
{
await FirebaseAuth.instance.signOut();
Navigator.of(context).pushNamedAndRemoveUntil(loginRoute, (_) => false,);
}
}
},
itemBuilder: (context) {
return const [
PopupMenuItem<MenuAction>(
value: MenuAction.logout,
child: Text('Logout'),
)
];
},
)
]
),
body: const Text("Hello world"),
);
}
}
Future<bool> showLogOutDialog(BuildContext context)
{
return showDialog<bool>(
context: context,
builder: (context)
{
return AlertDialog(title: const Text('Sign Out'),
content: const Text('Are you sure you want to sign out?'),
actions: [
TextButton(onPressed: () {
Navigator.of(context).pop(false);
}, child: const Text("Cancel")),
TextButton(onPressed: () {
Navigator.of(context).pop(true);
}, child: const Text("Log Out")),
]
);
},
).then((value) => value ?? false);
}
3
Answers
Move your navigator line to a seperate function and call the
handleNavigation()
function from inside youronSelected:
. This will remove the warning.In Flutter, managing multiple
BuildContexts
can be tricky. In your case, you are working with different contexts. One from your stateful widget and another from your build function, plus any additional contexts from Builder widgets likeLayoutBuilder
. The key issue here is correctly using the mounted property to check if the widget is still in the tree.Below are three options what you can do now.
Option 1: Use the widget’s context
Option 2: Use the local build function’s context
Option 3: Create a helper function outside the build function
Put your navigations inside a if check like this…