Initialized in initState but late error in didChangeDependencies - flutter

late bool onoff;
#override
void initState() {
super.initState();
_initUser();
}
#override
void didChangeDependencies() {
super.didChangeDependencies();
final pro = Provider.of<Pro>(context);
pro.firstsulonoff = onoff;
}
_initUser() async{
var test = await fireStore.collection('firstsul').doc('firstsul').get();
onoff = test["onoff"];
This is the code that receives Firebase's data from initstate before build is executed and puts it into the firstsulonoff variable of Provider from didChangeDependencies. Late error pops up.
LateInitializationError: Field 'onoff' has not been initialized.

Looks to me that _initUser should be in Pro and the widget should be stateless.

Related

FocusAttachment Is Not Working When Navigating Away and Back From Flutter Web

I have a Flutter app for web that checks if control is pressed, and is managed in my internal state. Using this answer I created the code to check if control is pressed. My code is below:
class _CanvasViewState extends ConsumerState<CanvasView> {
late final FocusNode focus;
late final FocusAttachment _nodeAttachment;
#override
void initState() {
focus = FocusNode();
_nodeAttachment = focus.attach(context, onKey: (node, event) {
// preform call to provider
return KeyEventResult.ignored;
});
focus.requestFocus();
super.initState();
}
#override
void dispose() {
focus.dispose();
super.dispose();
}
_CanvasViewState();
#override
Widget build(BuildContext context) {
_nodeAttachment.reparent();
....
}
}
This works fine initially. However, if I go to a different application and come back it no longer works. The function callback inside of my initState is no longer called when I press control. Am I going about checking if control is pressed completely wrong or how can this be accomplished?
Instead of initState() try using didChangeDependencies()
like this:
bool _init = true;
#override
void didChangeDependencies() {
if(_init == true){
focus = FocusNode();
_nodeAttachment = focus.attach(context, onKey: (node, event) {
// preform call to provider
return KeyEventResult.ignored;
});
focus.requestFocus();
_init = false;
}
super.didChangeDependencies();
}

Flutter : Why build widget runs first before the initState()?

This is my controller.dart file which checks if users is verified or not and then return the page according to the conditions.
My question is that why the build widget is executing first before initState() ? I tried to debug this code using breakpoints and noticed that build() widget is running first and then the initState()Why this is happening and how could I fix it ?
This is my code :
class _ControllerState extends State<Controller> {
late bool auth;
#override
Widget build(BuildContext context) {
return (auth==false) ? Onbording() : IndexPage();
}
#override
void initState() {
super.initState();
WidgetsBinding.instance!.addPostFrameCallback((_) async {
await this.checked_if_logged();
});
}
Future<void> checked_if_logged() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
if(prefs.getBool('verified')==true){
setState(() {
auth = true;
});
}else{
setState(() {
auth = false;
});
}
}
}
This is a snapshot of my debug code where the blue line is showing that it runs first before init and because the bool auth is a late type so it throws lateInitializationErrror and after that initState() is called which initializes the auth variable which rebuild the widget and removes the error
Update:
I noticed that when I replace the WidgetsBinding.instance!.addPostFrameCallback((_) with just check_if_logged(), the initState() is calling first but before completion of check_if_logged() the build widget executes first which again throws lateInitializationError
I don't know where you got addPostFrameCallback from or what you want to achieve, but this is not the way.
Your problem is, that checked_if_logged is async and there is no way to await an async method in initState. That is by design and there is no way around that.
The proper way to handle this is to use a FutureBuilder widget.
See What is a Future and how do I use it?

Using Provider in Widget's initState or initialising life-cycle

So while learning Flutter, it seems that initState() is not a place to use Providers as it does not yet have access to context which must be passed. The way my instructor gets around this is to use the didChangeDependencies() life-cycle hook in conjunction with a flag so that any code inside doesn't run more than once:
bool _isInit = true;
#override
void didChangeDependencies() {
if (_isInit) {
// Some provider code that gets/sets some state
}
_isInit = false;
super.didChangeDependencies();
}
This feels like a poor development experience to me. Is there no other way of running initialisation code within a Flutter Widget that has access to context? Or are there any plans to introduce something more workable?
The only other way I have seen is using Future.delayed which feels a bit "hacky":
#override
void initState() {
Future.delayed(Duration.zero).then(() {
// Some provider code that gets/sets some state
});
super.initState();
}
I have implemented as follows inside didChangeDependencies
#override
void didChangeDependencies() {
super.didChangeDependencies();
if (_isInit) {
setState(() {
_isLoading = true;
});
Provider.of<Products>(context).fetchAndSetProducts().then((_) {
setState(() {
_isLoading = false;
});
});
}
_isInit = false;
}
It's possible to schedule code to run at the end of the current frame. If scheduled within initState(), it seems that the Widget is fully setup by the time the code is running.
To do so, you can use the addPostFrameCallback method of the SchedulerBinding instance:
#override
void initState() {
super.initState();
SchedulerBinding.instance.addPostFrameCallback((_) {
// Some provider code that gets/sets some state
})
}
You can also use WidgetsBinding.instance.addPostFrameCallback() for this. They both behave the same for the purpose of running code once after the Widget has been built/loaded, but here is some more detail on the differences.
Note: be sure to import the file needed for SchedulerBinding:
import 'package:flutter/scheduler.dart';
you can have the Provider in a separate function and call that function within the initState()
bool isInit = true;
Future<void> fetch() async {
await Provider.of<someProvider>(context, listen: false).fetch();
}
#override
void initState() {
if (isInit) {
isInit = false;
fetch();
}
isInit = false;
super.initState();
}

Calling Provider custom method inside setState() caused error: or markNeedsBuild() called during build

I have a flutter widget state class as follow. I call Provider.of<AppData>(context, listen: false).recalculateCart(); inside initState().
When I run, I'm getting the error said setState() or markNeedsBuild() called during build.
How should I resolve those?
class CartPageState extends State<CartPage> {
final TextEditingController _couponController = TextEditingController();
#override
void initState() {
// TODO: implement initState
super.initState();
Provider.of<AppData>(context, listen: false).recalculateCart();
}
#override
Widget build(BuildContext context) {
if (Provider.of<AppData>(context, listen: false).selectedStoreId == null){
Provider.of<AppData>(context, listen: false).setPageAfterStoreSelection('cart');
return ChooseStorePage(title: 'Choose Store to Continue');
}
...
}
Also, here is the recalculateCart() function:
void recalculateCart() {
notifyListeners();
}
The problem is that there is a re build when the actual build hasn't finished yet, so you can put you function inside a addPostFrameCallback method to execute the function after the first build has finished, try the next:
#override
void initState() {
// TODO: implement initState
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
Provider.of<AppData>(context, listen: false).recalculateCart();
});
}

initState in Flutter return null on SQLite database?

I create a button to test the database. it returns a set of data. While i did in initState function, what i get is null.
#override
void initState() {
db.queryData('username').then((val) {
_userAuthData = val;
});
super.initState();
print(_userAuthData);
}```
** both async/await and future.then() works the same in button on press function.
you can execute async function on init method by using future
#override
void initState() {
super.initState();
Future.delayed(Duration.zero,()async{
final _userAuthData=await db.queryData('username');
print(_userAuthData);
});
});