Flutter - How to Update Home Route After Returning from MaterialPageRoute - flutter

This is my App's flow:
How do I update the Home Page when I press back and return to it from the MaterialPageRoute? I attempted to use the setState method in the dispose() method of MaterialPageRoute, but it gave me an error.

You can use Navigator.push(context,MaterialPageRoute(builder: (context) => TheSecondPage())).then((value) { setState(() {}); thus when you pop from TheSecondPage() you will immediatelly call the setState refreshing the page.

Actually, the Home Page is automatically updated, however I made a mistake by updating the variable within the dispose() method, which is invoked after the Home Page has been updated.

Related

how to force build when ever a page shows up in flutter

Hello hope you guys are ok.
the problem I'm facing is we have a main_page which leads to a page doing some changes on data which are show on the main page.
after some process if the user touches back button and goes to main_page app loads it from stack and the data are not shown because it does not get rebuilt.
I don't want to control back button because there are other pages which lead to data changing page and I also tried using valuelistenablebuilder but I don't know why it goes wild and gets into a screen refresh loop without even changing the valueListenable I used redux to manage the value.
actual reason I want main page to rebuild is to call a method. why do I not call that method in second page is complicated and because i don't want to.
in conclusion I want main page to rebuild whenever it shows up even when it's read from the stack or even is there a way to tamper with stack of the pages without visual changes to the user.
you need to use Shared preferences plugin
https://pub.dev/packages/shared_preferences
If I understood the question correctly
The flow should be:
Screen A
#override
void initState() {
loadSomeDataFromDB();
super.initState();
}
Screen B
#override
void initState() { *//INIT AS EXAMPLE*
changeSomeDataFromDB();
super.initState();
}
You can try this in Screen A
onPressed: () async {
bool? shouldLoadDataAgain = await
Navigator.of(context).push(PageRouteBuilder(
pageBuilder: (context, animation, secondaryAnimation) =>
const ScreenB(),
));
if(shouldLoadDataAgain!=null&&shouldLoadDataAgain ==true){
loadSomeDataFromDB();
}
},
and this in Screen B when user press back button
onPressed: () async {
Navigator.of(context).pop(true)
},
solution for my problem was that used redux store had an object and updating object property or a list does not count as variable change to redux so the widget wouldn't rebuild.

How to trigger route to a different page from a provider

I have a stateless page with a provider. I use Google AdMob to display ads (in_app_purchase package).
On the page I have a start button. onPressed event has below code to go to the next page:
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const NextScreen()),
);
To implement rewarded ad I have added code to onPressed event to detect whether the ads are required, and if so, instead of routing to the next page, a dialog box is displayed asking user to watch an ad. If the user accepts, this starts the ad process in the provider.
This all works great, but my problem is that when the reward is granted in the provider event, I do not know how to trigger the move to the next page.
The ad code in the provider class looks like this:
await _rewardedAd!.show(
onUserEarnedReward: (AdWithoutView ad, RewardItem reward) {
//here I can notify listeners to change the UI look, but not to trigger a page move
}
);
At that point I can notify listeners to change UI look, but not to trigger a page move. It would be useful to have some sort of a "function widget" that does nothing but listen for a value change and execute some code, but could not find such a thing.
At a time of desperation I even tried putting and invisible widget on the page to do that, but that triggers an error when I call navigator route from a widget that is being rebuilt.
It would be nice if button onPressed even could listen for provider change, but I don't know if this is possible.
What is the proper way to do this? I suspect this is a very common scenario. Is this even possible to achieve with a stateless widget and provider pattern? Must I switch to a stateful widget?
Ended up implementing this solution which works but seems a bit hacky and not sure if it will cause some problems with the widget tree.
Will accept a better solution.
In a nutshell, provider has a special trigger variable that now a StateFulWidget screen listens for in didChangeDependencies event.
In the provider I have this code to display the ad and listen for rewarded event:
await _rewardedAd!.setImmersiveMode(true);
await _rewardedAd!.show(
onUserEarnedReward: (AdWithoutView ad, RewardItem reward) {
//set the trigger and notify listeners
_startWorkoutTrigger = true;
notifyListeners();
});
I converted the page to a StatefulWidget and added this code to didChangeDependencies event:
#override
Future<void> didChangeDependencies() async {
super.didChangeDependencies();
if (Provider.of<Settings>(context, listen: false)
.getStartTrigger()) {
Provider.of<Settings>(context, listen: false).cancelStartTrigger();
Future.delayed(
Duration.zero,
() => Navigator.push(
context,
MaterialPageRoute(builder: (context) => const NextScreen()),
));
}
}

How to get context back (or rebuild) when "This widget has been unmounted, so the State no longer has a context"? happens?

I'm running my flutter app on Android emulator with VScode.
I want to show a relevant page on app when fcm notification is tapped. My app can receive a notification correctly when app is on background. The app will open up when I tap a notification. However it will show the page last opened and gives errors below:
E/flutter (23056): [ERROR:flutter/lib/ui/ui_dart_state.cc(199)] Unhandled Exception: This widget has been unmounted, so the State no longer has a context (and should be considered defunct).
E/flutter (23056): Consider canceling any active work during "dispose" or using the "mounted" getter to determine if the State is still active.
My code to listen fcm notification action on background is like this:
void initState() {
fcmListener = FirebaseMessaging.onMessageOpenedApp
.asBroadcastStream()
.listen((RemoteMessage message) {
Navigator.of(context).popUntil((route) => route.isFirst); // Errors happen here
// Open notification details page
Navigator.push(context, MaterialPageRoute(builder: (context) => ShowPage()));
});
}
I saw quite few people suggesting "if(mounted){}". It will prevent errors, however that is not an option to me as I still want to open a detals page even when "not mounted". Is there a way to rebuild a lost context like:
if(mounted) {
// open a page normally
} else {
// No context, so rebuild it
rebuildContext();
// Then open a page
}
Or even make the app keep context?
I put dispose() - still no luck
#override
void dispose() {
fcmListener.cancel();
super.dispose();
}
Edit: This app has a login function with Laravel passport and I followed https://medium.com/swlh/authenticating-flutter-application-with-laravel-api-caea30abd57 to built it. I noticed that dispose() is called on login(so context will be lost at this point?). Also, the page will open correctly from notification after restarting project on VScode(so it is rebuilding context at this point?).
I found a solution.
Followed below. Use "navigatorKey.currentContext" for context works fine.
https://stackoverflow.com/a/61773774/3213925

Navigating to the updated page in flutter

When I insert data from other page and pop this page to go back on the listing page, I have to refresh the listing page to get the updated list of data. I want to go back to the updated version of page without pressing refresh button. I am using pushNamed and also I want to have a back arrow button on the input page.
Using Navigator.push or Navigator.pushNamed returns a Future object to you.
This Future resolves when you use Navigator.pop in the your second screen.
Here is a basic example. Assuming you have function goToNewPage which you are calling to push a new Screen, you can do it like this.
class Screen1State extends State<Screen1> {
void goToNewPage (context) {
Navigator.of(context).pushNamed('screen2').then((_) {
// The screen2 has popped. so you can just call setState here to just rebuild
// You can do anything you want here, that needs to happen after the new page has been popped.
setState(() {});
});
}
... rest of your code.
Note, the actual implementation of what you should do inside the callback depends on how your widget is getting data. But you can do anything you want to do after your new page is popped inside that callback.

How to refresh the page when user comes back to it from any other page using back key?

I have a page which is calling multiple classes and different widgets
and by clicking on it user can hop to any page.
Currently the issue is I want to refresh the original page everytime it is shown to user.
When it is freshly loaded (causing no issue for now).
When user comes back to it from some other page using back key.
old data is shown on the page, which I am trying to get rid of.
I have tried using Navigator.push method (Observer class method) and tried to listen when user presses backkey.
but there are multiple pages serving unique requests and I don't want to link everyone with that first page.
as while clicking Navigator.pop(context) method i'll have to pass some string.
Does any one know
how can I refresh the page when users comes back to it using backkey.
Navigator.push returns a Future when the MaterialPageRoute passed into it is resolved. You could await that Future to know when some other view has popped back to it.
Example,
Navigator.of(context).push(MaterialPageRoute(
builder:
(context) => NewView(),
),
).then((_) {
// Call setState() here or handle this appropriately
});
Had the same issue, the following worked for me (below code is in FirstPage()):
Navigator.push( context, MaterialPageRoute( builder: (context) => SecondPage()), ).then((value) => setState(() {}));
After you pop back from SecondPage() to FirstPage() the "then" statement will run and refresh the page.
NavigatorObserver can listen to route changes.
You need to create your implementation overriding didPop, didPush etc.
Then you can pass it to navigatorObservers field of MaterialApp or Navigator