Flutter force screen update with initState - flutter

I have a StatefulWidget in which I load data from the server using the initState(). It is somethig like this:
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
initState() {
super.initState();
// ... Load the data
}
// build
}
When I use the Navigator.pop() or Navigator.pushNamed() it does not reinit the state. Is there any away to prevent this?

After you call 'pushNamed' in MyApp, wait until 'pushNamed()' will be returned which is occurred when 'pop()' is called.
After that, refresh data and call build() by calling 'setState()'.
await Navigator.pushNamed(context, "/somePage");
...
[call reloadData sentence]
...
setState(() {});

Related

How to execute function when a variable is not null Flutter

I have this code in _MyAppState in my main.dart :
var _p3provider;
#override
void initState() {
super.initState();
P3provider p3provider = new P3provider();
authentification(p3provider);
_p3provider = p3provider;
}
I pass the variable _p3provider as p3provider to MyHomePage statefulWidget of my main.dart,
Here is some code of _MyHomePageState :
void initState() {
super.initState();
if (widget.p3provider.jsession_id == null) {
Future.delayed(Duration(seconds: 2), (){
getTasks();
});
} else {
getTasks();
}
}
To execute my getTasks function I need the jsession_id variable from p3provider object to be initialized. This variable is initialized in the initState of _MyAppState at this line : authentification(p3provider); .
The problem is that both the initState of _MyAppState and _MyHomePageState are executed at the same time so if I directly call getTasks() in the initState of _MyHomePageState it will return an error because p3provider.jsession_id will not have been initialized yet.
To avoid this error I used a Future.delayed after a checking if the variable is null, but I don't think this solution is optimal, I would like the function getTasks() to be executed directly when jsession_id become not null.
If anyone has an idea on how to do this, you are more than welcome ! :)
Found a solution :
I define this class :
class HomePageController{
var getTasks;
}
Which I instanciate in _MyAppState :
final HomePageController myController = HomePageController();
I pass it down to MyHomePage widget :
home: MyHomePage(controller: myController),
And in the initState of _MyHomePageState I assign my function getTasks() to the controller variable getTasks :
#override
void initState() {
super.initState();
widget.controller.getTasks = getTasks;
}
Now I can execute getTasks via the controller in _MyAppState :
#override
void initState(){
super.initState();
authentification().then((value){
myController.getTasks();
}
Here is the topic where I got it : Flutter calling child class function from parent class

setState is not updating the UI even though state is updating

I am trying to wait till amplify configuration is done then load the login screen. Even though state seems to be getting updated I am still getting the loadinscreen. Why is that?
I am not sure if setState is proper method on the init : Importance of Calling SetState inside initState
As per the doc : https://docs.amplify.aws/start/getting-started/integrate/q/integration/flutter/#configure-amplify
Future<void> main() async {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
MyApp({Key? key}) : super(key: key);
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
bool _isAmplifyConfigured = false;
late AmplifyAuthCognito auth;
#override
void initState() {
_initializeApp();
super.initState();
}
Future<void> _initializeApp() async {
await _configureAmplify();
setState(() {
_isAmplifyConfigured = true;
});
}
Future<void> _configureAmplify() async {
auth = AmplifyAuthCognito();
try {
await Amplify.addPlugin(auth);
await Amplify.configure(amplifyconfig);
} on AmplifyAlreadyConfiguredException {
print(
'Amplify was already configured. Looks like app restarted on android.');
}
}
#override
Widget build(BuildContext context) {
return MaterialApp(
onGenerateRoute: AppRoutes.onGenerateRoute,
initialRoute: _isAmplifyConfigured
? LoginScreen.routeName
: LoadingScreen.routeName,
);
}
}
I think the issue is with you trying to reassign your initialRoute. I'm not super familiar with this property, but given the name I assume this is set once and is not rebuilt, not even when the state changes. It would make sense, also, because the rest of your code sounds like it should work.
Before trying anything else, I'd recommend you move your logic to initialize Amplify to the LoginScreen, and having its body depend on the _isAmplifyConfigured boolean value. So show spinner if it's false, and show Login fields when it's true.
Even better would be to create a HomeScreen, so you can keep this Amplify initialization at the bottom of your app's stack. And then have your HomeScreen either show the Login widgets, the home screen of your app, or a loading state.

Access function defined in MyApp() class - Flutter

I would like to access a function defined in my top level class from another class. How can i do that ?
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp>
{
void startListeningNotifications()
{
//start listening to fcm messages
}
void initState()
{
super.initState();
startListeningNotifications();
}
}
I want to call this function startListeningNotifications() from another class. Is that possible ?
I am already calling this function in initState() but there are some cases in which i need to call it from some other class. For example, if a user isn't already registered with your Firebase-app, then after the registration process, i need to access this method in order to start listening to fcm notifications.
You can define startListeningNotifications() in a different file, import it into any page you need and call it there.
// create lib/_utils/fcm_utils.dart
void startListeningNotifications() {
// your function
}
...
// main.dart or any page you want to call your functions from
// TODO: replace yourAppName below with your app name
import 'package:yourAppName/_utils/fcm_utils.dart';
...
void initState() {
super.initState();
startListeningNotifications();
}

How to use the same BLoC for different widgets in Flutter?

I have 2 custom widgets, and I want to use the same Bloc file.
My Bloc file gets data from the internet in the constructor.
class MyBloc {
// StreamControllers, StreamSinks, Streams ...
MyBloc() {
getDataFromInternet();
}
}
class MyWidget1 extends StatefulWidget {
MyWidget1({Key key}) : super(key: key);
#override
_MyWidget1State createState() => _MyWidget1State();
}
class _MyWidget1State extends State<MyWidget1> {
MyBloc _bloc;
#override
void initState() {
_bloc = MyBloc();
super.initState();
}
}
class MyWidget2 extends StatefulWidget {
MyWidget2({Key key}) : super(key: key);
#override
_MyWidget2State createState() => _MyWidget2State();
}
class _MyWidget2State extends State<MyWidget2> {
MyBloc _bloc;
#override
void initState() {
_bloc = MyBloc();
super.initState();
}
}
My problem is, that it downloads the data every time the screen changes (any of the two widgets appear on the screen).
Should I pass the initialized bloc object to the widgets in the constructors, and not create a new Bloc in the widgets constructor? I don't want to save the data and write logic to check if I already downloaded it or not.
Use this bloc implementation https://bloclibrary.dev/
Your bloc will have single instance with it's single state at the moment. Invoke new state depending on previous and you will never has problems with unneeded queries or something like this.

initState() not called when building stateful widget

I am trying to build a widget and do something in the initState() function. I have done it before in other cases, but this time the initState() is just not called. I have put breakpoints, the application goes into the constructor (assert line) and the object in the assert is not null, so it should go on and initialize the state. But it doesn't, and I don't understand why.
Any help would be greatly appreciated. Thanks.
Here's the code:
class MyWidget extends StatefulWidget {
SomeOtherObject someOtherObject;
MyWidget({#required this.someOtherObject})
:
assert(someOtherObject != null)
;
#override
_MyWidgetState createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
#override
void initState() {
super.initState();
// widget.someOtherObject.addListener(update);
}
#override
Widget build(BuildContext context) {
// ...
}
}
I would redirect you to this answer: initState function is't be called in StatefulWidget by default
Your code works just fine in a DartPad, make sure you fully restart your app, not just hot reload. Often times for me, Flutter likes to use an old version of my app so I have to hot restart. Also, just so you know, any time you edit initState(), you MUST hot restart your app for the changes to take effect.