In Flutter Flame, I have an overlay expressed by a widget. I wish to rebuild the widget whenever the dependency changes, but I'm unclear how to do this in Flutter Flame.. there seems to be no mention of this in the documentation anywhere. How do I do this?
Reviewed the Flame documentation but it is not mentioned.
My only solution is to make an "update" widget that I run whenever update in the game is called.. then I call setState on the widget. Very hacky and non-performant!
late UpdateComponent t;
#override
void initState() {
super.initState();
t = UpdateComponent(
(p0) {
setState(() {});
},
);
widget.game.add(t);
}
#override
void dispose() {
super.dispose();
widget.game.remove(t);
}
Related
Im using getx and i want to call api after bage build, because this api its not necessary part of the page build.. What i know is this way
#override
void initState(){
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_){
});
}
But what about getx best way ?
the Getx package offers lifecycle methods that are very convenient in you're cases, what you need here is to use the onReady(), which is called one frame after the onInit() is executed, you can say that its equivalent to the:
#override
void initState(){
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_){
// Here is the code which will be executed exactly after initState using StatefulWidget
});
}
you can use onReady() like this:
class TextController extends GetxController {
#override
void onInit() {
/*...*/
}
void onReady() {
// Here is the code which will be executed exactly after onInit using Getx
}
}
I had an error every time I restarted my App: This widget has been unmounted, so the State no longer has a context (and should be considered defunct). and saw that something was not correct with my initstate. The initState was:
#override
void initState() {
SchedulerBinding.instance.addPostFrameCallback((_) {
BlocProvider.of<TutSkippedCubit>(context).load();
});
super.initState();
}
the methods loads the data from sharedprefs if I have already skipped the tut or not. Now I solved this issue with removing the initState method and putting the function call inside the widget build:
#override
Widget build(BuildContext context) {
BlocProvider.of<TutSkippedCubit>(context).load();
....
The widget build gets called when the pages loads, so, isn't it the same as the initial state? For what exactly is the methode initState() and I have the feeling that my way of handling this problem is a bad practise, but what would be a better way, how do I solve it?
The initState() method is to control what happens after the app is built. The problem is that you call BlocProvider before the app begins. The correct way is to put all the actions after super.initState() call and add the context to the BlocProvider inside build method. Like this:
TutSkippedCubit? tutSkippedCubitProvider;
#override
void initState() {
super.initState();
SchedulerBinding.instance.addPostFrameCallback((_) {
tutSkippedCubitProvider!.load();
});
}
#override
Widget build(BuildContext context) {
tutSkippedCubitProvider = BlocProvider.of<TutSkippedCubit>(context);
...
}
The initState and build method is called when the widget is inserted into the widget tree, but the build method also is called every time the state is changed.
You do need to have in mind that every time the state is changed your method BlocProvider.of<TutSkippedCubit>(context).load(); also is called.
Maybe, the code below can help you:
WidgetsBinding.instance.endOfFrame.then(
(_) async {
if (mounted) {
BlocProvider.of<TutSkippedCubit>(context).load();
}
},
);
You wouldn't be surprise of getting that error since you are using BlocProvider.<T>(context) out of a BuildContext. This context in bracket is the just the same as the one given in the build function.
The initState() is a method that is called when an object for your
stateful widget is created and inserted inside the widget tree.
i'm building a simple app that prints the result of the current TextFormField. Such as when the text changes it prints the new value.
I found out that you can achieve this with TextEditingController.addListener that listens for changes and executes a function.
So i wrapped it all in initState as follows
#override
void initState() {
addressController.addListener(() {
print(addressController.text);
});
The problem I have is that sometimes it records changes even when there aren't any:
This is what happens writing a word and then deleting it.
If you add listener then you should remove it somewhere, otherwise there can be situation when TextEditingController will have 2 or more listeners:
#override
void initState() {
addressController.addListener(_addressControllerListener);
super.initState()
}
void _addressControllerListener() {
print(addressController.text);
}
#override
void dispose() {
addressController.removeListener(_addressControllerListener);
super.dispose()
}
I'm developing android/ios app using flutter with provider(state management)
in my app, i have a Main scaffold with bottom navigation menu. (so, one scaffold with many views and controll it using bottom navigation, NOT Navigator.push())
i want to know that is it possible recall initstate() from build().
for example
... Statefulwidget
void initState() {
super.initState();
MYHttp.callAPI_only_once_for_some_reason();
}
Widget build(...) {
var flag = Provider.of<MyProvider>(context).flagdata; // flag is true when push notification has been arrived
if (flag) {
initstate() // apparently it should not work, but i have to recreate whole stateful widget to call initState()
}
}
No it is not possible. The initstate() is only called each time a new widget is painted.
Instead of recalling the initstate. Create a method, add it to use init state and call wherever you want to call it.
Check the code below for an example. It works perfectly:
// create the method.
void makeRequest() {
MYHttp.callAPI_only_once_for_some_reason();
}
void initState() {
//call the created method here
makeRequest();
super.initState();
}
Widget build(...) {
var flag = Provider.of<MyProvider>(context).flagdata; // flag is true when push notification has been arrived
if (flag) {
// call the method here again. if you need to use it.
makeRequest(); // apparently it should not work, but i have to recreate whole stateful widget to call initState()
}
}
I hope this helps.
I hope I understand how didChangeAppLifecycleState worked correctly.
I have page A and page B . When I click the back device button from page B ( Navigator.of(context).pop(); ), I expect didChangeAppLifecycleState in pageA will get called, but it doesn't.
PageA
class _ABCState extends State<ABCrList> with WidgetsBindingObserver {
#override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
....
}
#override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
#override
void didChangeAppLifecycleState(AppLifecycleState state) {
if (state == AppLifecycleState.resumed) {
setState(() {
print(...);
});
}else{
print(state.toString());
}
}
....
This is the initState in pageA. The function used to call backend service.
#override
void initState() {
super.initState();
_bloc.getList(context); // return list and populate to ListView
});
}
The way you're thinking it is Android's way where onResume works, but in Flutter, things don't happen this way.
Generally, this gets called when the system puts the app in the background or returns the app to the foreground.
There are mainly 4 states for it:
resumed: The application is visible and responding to user input.
inactive: The application is in an inactive state and is not receiving user input.
paused: The application is not currently visible to the user, not responding user input, and running in the background.
detached: The application is still hosted on a flutter engine but is detached from any host views.
Edit:
When you're navigating to PageB from PageA, use something like:
Navigator.pushNamed(context, "/pageB").then((flag) {
if (flag) {
// you're back from PageB, perform your function here
setState(() {}); // you may need to call this if you want to update UI
}
});
And from PageB, you'll can use
Navigator.pop(context, true);