initState in Flutter return null on SQLite database? - flutter

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);
});
});

Related

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?

Flutter how to invoke initState() properly

Hi IM trying to load initial data from db and sharepref as user first open page.
...
List questionsList = [];
bool _languageA = false;
#override
void initState() {
super.initState();
loadData(); // seting for some dropdown menu
_getLanguageChoise(); //geting from sharepref bool value
_getData(arabic: _languageArabic).then((value) { //async db call load List ext...
setState(() {});
});
}
Problem is that "questionsList" and "_languageA" bool is not filed in initState , so I get null or initial value, only when I refresh state or reload
List get filed and var get value... So what I need to do in order to have initial filed variables before build method so user can see..
assign questionsList and _languageA values inside initState method just like this in order to initialize a field value when the widget is created
void initState() {
super.initState();
questionsList=["hello"];
_languageA=true;
}
Make your initstate like this
#override
void initState() {
super.initState();
questionsList=[""];
_languageA=true;
loadData(); // seting for some dropdown menu
_getLanguageChoise(); //geting from sharepref bool value
_getData(arabic: _languageArabic).then((value) { //async db call load List ext...
setState(() {});
});
}

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();
});
}

Unhandled Exception: inheritFromWidgetOfExactType(_LocalizationsScope) or inheritFromElement() was called before _ScreenState.initState() completed

I am calling initial method to load data from API using initState. But it is resulting me an error. Here is error:
Unhandled Exception: inheritFromWidgetOfExactType(_LocalizationsScope) or inheritFromElement() was called before _ScreenState.initState() completed.
When an inherited widget changes, for example if the value of Theme.of() changes, its dependent widgets are rebuilt. If the dependent widget's reference to the inherited widget is in a constructor or an initState() method, then the rebuilt dependent widget will not reflect the changes in the inherited widget.
My code is:
#override
void initState() {
super.initState();
this._getCategories();
}
void _getCategories() async {
AppRoutes.showLoader(context);
Map<String, dynamic> data = await apiPostCall(
apiName: API.addUser,
context: context,
parameterData: null,
showAlert: false,
);
if(data.isNotEmpty){
AppRoutes.dismissLoader(context);
print(data);
}else {
AppRoutes.dismissLoader(context);
}
}
You need to call _getCategories after initState has completed.
#override
void initState() {
super.initState();
Future.delayed(Duration.zero, () {
this._getCategories();
});
// Could do this in one line: Future.delayed(Duration.zero, this._getCategories);
}
Also, you could do this on a different way, using addPostFrameCallback.
To make this task easier, you could create a mixin to be added to StatefulWidgets.
mixin PostFrameMixin<T extends StatefulWidget> on State<T> {
void postFrame(void Function() callback) =>
WidgetsBinding.instance?.addPostFrameCallback(
(_) {
// Execute callback if page is mounted
if (mounted) callback();
},
);
}
Then, you just need to plug this mixin to you page, like that:
class _MyPageState extends State<MyPage> with PostFrameMixin {
#override
void initState() {
super.initState();
postFrame(_getCategories);
}
}
Use the didChangeDependencies method which gets called after initState.
For your example:
#override
void initState() {
super.initState();
}
#override
void didChangeDependencies() {
super.didChangeDependencies();
this._getCategories();
}
void _getCategories() async {
// Omitted for brevity
// ...
}
Adding a frame callback might be better than using Future.delayed with a zero duration - it's more explicit and clear as to what is happening, and this kind of situation is what frame callback was designed for:
#override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) async {
_getCategories();
});
}
an alternative is to put it inside PostFrameCallback which is between initState and Build.
#override
void initState() {
WidgetsBinding.instance.addPostFrameCallback((_) => getData());
super.initState();
}
getData() async {
}
There are many ways to solve this problem, override initState method:
#override
void initState() {
super.initState();
// Use any of the below code here.
}
Using SchedulerBinding mixin:
SchedulerBinding.instance!.addPostFrameCallback((_) {
// Call your function
});
Using Future class:
Future(() {
// Call your function
});
Using Timer class:
Timer(() {
// Call your function
});
The best solution i think is use the context from the Widget build. And paste the method _getCategories(context) after the build with the context from the tree.
So there is no problem with the widget tree.