I am building a flutter application in which I have 2 screens.I have API calls on both screens.When I navigate on 2nd screen and return back to 1st screen then build function of 1st Screen runs as expected and API is called again(In future of FutureBuilder) which I don't want. I only want to update or fetch the API when I slide from top to bottom on screen.But due to FutureBuilder in my !st screen's build function it is fetching the data again and again everytime.
Any suggestion with e.g. code will be helpful.Thank you!
you can use StatefullWidget and have a property in State class like Future<String>
and assing it in initState.
if you back from second screen your build function called but you have previous data.
...
Future<String> future;
initState(){
future = apiCall();
}
Widget build(){
return FutureBuilder(
future: future,
);
}
Related
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.
I have this screen with no list of data to show in this empty screen also when I pull down I wanna perform the refresh indicator function but I don't know how to do it. when there is a list of data pull to refresh works perfectly fine but if there is no data pull to refresh doesn't work is there a way to achieve pull to refresh in an empty screen like this also. thanks
Yes, with RefreshIndicator Widget, it's very simple, wrap the whole page in RefreshIndicator Widget, and just keep in mind that you should make the onRefresh function to return Future, because after getting the data, there is 2 things to be handled:
the widget will handle the CircularProgressIndicator just after the onRefresh function gets the data, that is why I used await at the code example, to make the widget know when the function is finished.
you should update the state, like this code, I'm using bloc to update it, you are free to use any stage management else:
RefreshIndicator(
onRefresh: () async {
await _bloc.pull();
}
child: .....,
);
For more tutorial check this video.
YOU Can wrap your entire screen with a refreshIndicator, and you get access to the refresh function.
body: RefreshIndicator(
onRefresh: () async {
fetchData();
},
child:// your other widgets here
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.
I am struggling with the following problem:
I built a list of widgets using StreamBuilder (and made it searchable). The widgets are Cards and inside them the user can make his selection and then push a button.
Everything is (was) working just fine.
Then I wanted to add a little animation and make the Icon associated to the button an animated one.
Now it is a mess, the StreamBuilder is in an infinite loop and I have also some problem on my list. If I comment out the animated icon and put in again the previous Icon ...everything starts to work fine again.
...
child: FloatingActionButton(
onPressed: (){
addFood();
mealListState.getAcontroller(id).forward();
},
child:
// MyAddIcon(id), //--> my animated Icon. It does not work
Icon(Icons.add), //--> it works
....
I read that the problem is that adding States management (Unnecessary Widget Rebuilds While Using Selector (Provider) inside StreamBuilder) inside the stream mess things up and that you have to make the widget building the stream Stateful and set up the stream in the initState.
I tried to follow this way but I need the context to build my card list, so I could follow the above hint just to read the data from db (firestore) and ...it is not enough
Could someone point me in the right direction or I have to leave the idea and move on?
Thanks
If you need the context, you can try to listen to the the stream in the didChangeDependencies method of your State class.
Use the Streamsubscription returned by stream.listen to cancel your subscription like so to avoid subsribing twice or even more times:
#override
didChangeDependencies() {
final stream = Provider.of<MyStream>(context); // context available here.
if (this.streamsubscription != null) {
this.streamsubscription.cancel();
}
this.streamsubscription = stream.listen((value) {
// your callback code here
});
super.didChangeDependencies(); // important
}
Ok, I am working on a media player app using flutter. Now when I press the play button, it changes to pause button. (Only the icon on the button changes)
The onPressed function for the button changes a boolean value and calls the setState() method.
It goes something like this.
bool _playing = false;
void _onPlayButtonPressed() {
setState () {
if (_playing)
_playing = false;
else
_playing = true;
}
}
I also have a function that returns the icon based on the value of _playing.
Widget _playButtonIcon() {
//This function has no setState() call
if (_playing)
//return pause icon
else
//return play icon
}
Everything works fine. The icon changes everytime I press the button. However as mentioned in docs and also in Flutter Demo App, setState() method calls the build method. Which redraws the entire widget tree including child widgets that are completely unchanged.
Is this approach justified or is this an overkill?
Do I have to put the button on a different Stateful Widget Class and call its build method via setState() everytime I tap this playButton?
What if I have other widgets that also changes the state of UI. Possibly changing different widgets?
What is the proper way to do this without having a performance hit?
Creating a play button that is a widget of its own with a state that maintains whether it is playing or not definitely makes sense. Now when you call setState on the parent widget it does call the build method, but as far as I know it does not necessarily redraw everything from scratch. If no changes are found in some of the embedded widgets it does not redraw them since they are already in the widget tree. Finally, it is okay to call setstate, however if your app starts getting bigger and you find yourself calling set state in too many places, and want to use global keys, I would advise looking into the Provider package, and making use of the ChangeNotifier/Consumer pattern.