Using RouteObserver to Refresh a widget when you go back
In a recent project, I ran into an issue where I needed to refresh a page when the user navigated back to it. After searching on google and asking ChatGPT, I found this simple and clean solution.
What is RouteObserver?
RouteObserver
is part of the Flutter framework that helps you track navigation events in your app. It allows you to listen to changes in the route stack, such as when a route is pushed or popped. This is incredibly useful for scenarios where you need to refresh or update your UI based on navigation.
Setting Up RouteObserver
First, I created a UserSession
class to hold a singleton instance of RouteObserver
. Here’s the gist:
// user_session.dart
import 'package:flutter/material.dart';
class UserSession {
static final UserSession _instance = UserSession._internal();
static final routeObserver = RouteObserver<ModalRoute>();
UserSession._internal();
}
By doing this, I could easily access routeObserver
from anywhere in my app. My UserSession also holds other user session data, maybe a bettway is to create a separate file for RouteObserver. But for now, we just use the UserSession class.
Adding RouteObserver to Your App
Next, I needed to register this RouteObserver
with my app’s navigator. I did this in the main app widget:
// main.dart
import 'package:flutter/material.dart';
import 'package:happy_notes/screens/account/user_session.dart';
class HappyNotesApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: const InitialPage(),
navigatorObservers: [UserSession.routeObserver],
);
}
}
By adding UserSession.routeObserver
to navigatorObservers
, we’re now tracking route changes across the entire app.
Using RouteObserver in Screens
To use RouteObserver
, I extended my state classes with RouteAware
and subscribed to the routeObserver
in the initState
method. Here’s an example from the Memories
screen:
// memories.dart
import 'package:flutter/material.dart';
import '../account/user_session.dart';
class MemoriesState extends State<Memories> with RouteAware {
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
UserSession.routeObserver.subscribe(this, ModalRoute.of(context)!);
});
}
@override
void didPopNext() {
// Called when the top route has been popped off, and this route shows up
_fetchMemories();
setState(() {});
}
@override
void dispose() {
UserSession.routeObserver.unsubscribe(this);
super.dispose();
}
void _fetchMemories() {
// Logic to refresh memories
}
}
Here’s what’s happening:
- Subscription: In
initState
, the screen subscribes torouteObserver
. - Route Events: The
didPopNext
method is triggered when the screen becomes visible again after another screen is popped off. This is where I refreshed the screen's data by calling_fetchMemories()
. - Unsubscription: It’s important to unsubscribe in the
dispose
method to avoid memory leaks.
Conclusion
Using RouteObserver
in Flutter allows you to manage your app’s navigation state effectively. By listening to route changes, you can ensure that your UI stays in sync with user actions, providing a seamless experience.