Sometime in out application we want to refresh a page or widget on navigation pop/back in flutter because we want to update the state of our page so users can see the latest update based on their actions. So In this article I will show you to flutter refresh page on back.
In Flutter application we heavily use Navigator APIs to navigate between the pages, in some scenarios we need to update the screen on pop so we can show the latest data. in this article we will learn to refresh the screen using two methods as follow
Method 1 : Flutter Refresh page on back using async await on Navigator push
In this method we will use async await to update the page, flutter provides promise on complete of navigator function so we can wait for the completion of navigation and update the screen using async await as below
Step 1 : Create flutter project
Very first step is to create the fluter application using command line tool or in Android studio.
flutter create example_app
This will create a new project with name my_app then go in to the folder.
Step 2 : Create two widgets for navigation
Now, Create two widgets to navigate between the pages. Let’s create one widget name as Home
and Second as Products
. From home screen we will pass params to it and will access it to another page which is Products.
File : lib/Home
.dart
class Home extends StatelessWidget {
const Home({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Home'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text("Home Screen"),
Text("Home Screen Count "+ count.toString()),
ElevatedButton(onPressed: () async {
await Navigator.pushNamed(context, '/Products',arguments:{"id":1,"name":"apple"});
//do your stuff after completion of navigator
}, child: const Text("Navigate to Apple")),
ElevatedButton(onPressed: (){
Navigator.pushNamed(context, '/Products',arguments:{"id":2,"name":"Nokia"});
}, child: const Text("Navigate to Nokia"))
],
),
),
);
}
}
Here we used Navigator.push
to navigate to another page which is Products
and also used Scaffold for material mobile design. As you can see we used arguments
to pass the params to another page.
and used async await here
ElevatedButton(onPressed: () async {
await Navigator.pushNamed(context, '/Products',arguments:{"id":1,"name":"apple"});
//do your stuff after completion of navigator
}
lib/
.dartProducts
class Products extends StatelessWidget {
const Products({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
Map arguments = ModalRoute.of(context)?.settings.arguments as Map;
return Scaffold(
appBar: AppBar(
title: Text('Product ${arguments['name']}'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text("${arguments['name']} and id ${arguments['id']}"),
ElevatedButton(onPressed: (){
Navigator.pop(context);
}, child: const Text("Navigate back"))
],
),
),
);
}
}
We used here Navigator.pop
to go back to the last page.
Step 3 : Add Routing widget
Now create routing for these two pages using MaterialApp
. As you can see in below example we have created two routes /
to access the home screen and /Products
to access the products page.
We also create builder using Navigator and in Navigator we implemented onGenerateRoute
to create MaterialPageRoute
to access the params between pages.
class AppRouter extends StatelessWidget {
const AppRouter({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Named Routes Demo',
\\this is optional
builder: (context, widget) => Navigator(
onGenerateRoute: (RouteSettings settings) => MaterialPageRoute(
builder: (ctx) {
return Container(
child: widget,
);
},
),
),
\\this is optional
initialRoute: '/',
routes: {
'/': (context) => const Home(),
'/Products': (context) => const Products(),
});
}
}
Step 4 : Add Page to main file
Simply run the project using command line or in android studio to check the implementation.
import 'package:flutter/material.dart';
import 'package:example_app/AppRouter.dart';
import 'package:example_app/Home.dart';
import 'package:example_app/Products.dart';
void main() {
runApp(const AppRouter());
}
Method 2 : Refresh page RouteObserver and RouteAware to get the Navigator events in widget
In this method we will use RouteObserver
and RouteAware
to the widget. RouteObserver provides events of navigator apis in widget so we can implement RouteAware
methods in our widget.
In this example we will create routing, two widgets as above but also a service so we can create RouteObserver in that service and use it across the widgets as below
Step 1 : Create a class
Let’s create a simple class named as Helper so that we can use it across multiple files
import 'package:flutter/material.dart';
class Helper {
static final RouteObserver<PageRoute> _routeObserver = RouteObserver();
}
Step 2 : Update AppRouter Widget
Now update the AppRouter.dart file and add navigatorObservers: [Helper.routeObserver]
in
class AppRouter extends StatelessWidget {
const AppRouter({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Named Routes Demo',
navigatorObservers: [Helper.routeObserver],
initialRoute: '/',
routes: {
'/': (context) => const HomePage(),
'/Products': (context) => const Products(),
});
}
}
Step 3 : Update Widget and add RouteAware mixing to widget
Now update the AppRouter.dart file and add navigatorObservers: [Helper.routeObserver]
in
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> with RouteAware {
@override
void didPush() {
print('HomePage: Called didPush');
super.didPush();
}
@override
void didPop() {
print('HomePage: Called didPop');
super.didPop();
}
@override
void didPopNext() {
print('HomePage: Called didPopNext');
super.didPopNext();
}
@override
void didPushNext() {
print('HomePage: Called didPushNext');
super.didPushNext();
}
@override
void initState() {
WidgetsBinding.instance!.addPostFrameCallback((timeStamp) {
Helper.routeObserver.subscribe(this, ModalRoute.of(context)!);
});
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Home'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text("Home Screen"),
ElevatedButton(
onPressed: () {
Navigator.pushNamed(context, '/Products',
arguments: {"id": 1, "name": "apple"});
},
child: const Text("Navigate to Apple")),
ElevatedButton(
onPressed: () {
Navigator.pushNamed(context, '/Products',
arguments: {"id": 2, "name": "Nokia"});
},
child: const Text("Navigate to Nokia"))
],
),
),
);
}
}
Here we added
@override
void initState() {
WidgetsBinding.instance!.addPostFrameCallback((timeStamp) {
Helper.routeObserver.subscribe(this, ModalRoute.of(context)!);
});
super.initState();
}
and methods
- didPop(): Called when we call pop method of navigator.
- didPopNext(): In this method, on the off chance that you have extended HomePage with RouteAware, and in case SecondPage is popped so HomePage is noticeable now, didPopNext is called.
- didPush(): called when the current screen or route has been pushed into the navigation stack.
- didPushNext(): called when a new screen/route is pushed from the current screen and the current screen is no longer visible.
Check the implementation here and you can check the console for logs