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(() {});
});
}
Related
I'm using Shared preferences to save the user's name and login state even after closing the app. the Shared Preference I used in main.dart is fine because I used it in the main function and made it async, but when I'm trying to use it in other classes, I see a dark red screen for less than a second before loading the page and it makes my app so ugly. what can I do to fix it?
Here's my code:
late bool _isEditingText;
TextEditingController _editingController = TextEditingController();
late String initialText ;
SharedPreferences? _prefs;
#override
void initState(){
super.initState();
initializePreference().whenComplete((){
setState(() {});
});
}
Future<void> initializePreference() async{
_prefs = await SharedPreferences.getInstance();
String? name = _prefs?.getString('name');
if (name == null) {
_isEditingText = true;
initialText = 'Enter ur name';
} else {
_isEditingText = false;
initialText = name;
}
}
Update:
sorry for not including my exact error... here it is :
LateInitializationError: Field '_isEditingText#37486951' has not been initialized.
I think you are performing setState before all widgets are get initialised. So for that you can update initState as below:
void initState(){
super.initState();
WidgetsBinding.instance!.addPostFrameCallback((_) async {
initializePreference().whenComplete((){
setState(() {});
});
});
}
If it's not causing issue, than you have to show loading indicator. Like initially when there is no data indicator will be there and once you get data from SharedPreference in setState - you have to remove indicator and load your data.
You can use CircularProgressIndicator for that.
initialise your boolean variable,
var isDataLoad = false;
once you get data in whenComplete(), set it as true and based on this variable you can declare your widgets.
isDataLoad ? Container( // Your widgets where you use "initialText" ) : CircularProgressIndicator();
You can see the strange behaviour in this video: https://streamable.com/r5ld2y
The InitValue is the correct one, but when I restart the App it first goes to zero, AFTER loading the Screen OR press a button, it loads the shared prefs...
This is my Cubit (Only with the LoadCounter Func):
class DrinkCubit extends Cubit<DrinkState> {
DrinkCubit() : super(DrinkState(drinkValue: 0));
Future<void> loadCounter() async {
final prefs = await SharedPreferences.getInstance();
state.drinkValue = (prefs.getInt('counter') ?? 0);
}
}
And this is my InitFunction in the main window!
#override
void initState() {
super.initState();
Future.delayed(Duration.zero,()
{
BlocProvider.of<DrinkCubit>(context).loadCounter();
});
}
So how do I fix this, that the correct value is directly after starting the app showed
Try this:
getData(){
BlocProvider.of<DrinkCubit>(context).loadCounter();
}
#override
void initState() {
SchedulerBinding.instance.addPostFrameCallback((_) {
getData();
});
super.initState();
}
SchedulerBinding.instance.addPostFrameCallback ensures that code inside run before UI code.
And if it allows me to give you a hint, is better remove SharedPreferences of your Bloc and put in another class.
I'm building a Flutter app, and have a page with a table that is populated with data. I load the data like so:
class _AccountMenuState extends State<AccountMenu> { {
List<Account> accounts;
Future<List<Account>> getAccounts() async {
final response = await http.get('http://localhost:5000/accounts/' + globals.userId);
return jsonDecode(response);
}
setAccounts() async {
accounts = await getAccounts();
}
#override
void initState() {
setAccounts();
super.initState();
}
}
This works as expected when hot reloading the page, but when I route to this page via MaterialPageRoute,
like so: Navigator.push(context, MaterialPageRoute(builder: (context) => AccountMenu()));
then the data is not there.
What am I missing? I thought initState() gets called whenever a page loads?
You cannot do setState inside initState directly but you can wrap the initialization inside a PostFrameCallback to make sure that the initState lifecycle of the Widget is done.
class _AccountMenuState extends State<AccountMenu> { {
List<Account> accounts;
Future<List<Account>> getAccounts() async {
final response = await http.get('http://localhost:5000/accounts/' + globals.userId);
return jsonDecode(response);
}
setAccounts() async {
accounts = await getAccounts();
setState(() {})
}
#override
void initState() {
WidgetsBinding.instance.addPostFrameCallback((_) => setAccounts());
super.initState();
}
}
initState() will not wait for setAccounts() to finish execution. In the method setAccounts() call setState after loading data.
setAccounts() async {
accounts = await getAccounts();
setState((){});
}
initState does not await. It only loads functions before the widget builder but it does not await.
you need to await loading widgets with data until accounts.length is not empty.
Show loading widget while data still loads or use FutureBuilder
List<Account> accounts;
#override
void initState() {
setAccounts();
super.initState();
}
#override
Widget build(BuildContext context) {
accounts.length > 0 ? SHOW_DATA_HERE : LOADING_WIDGET_HERE
}
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);
});
});
In the init state, I add an if statement to check to see if a custom widget exists on the list that I will pass to the Listview.builder, called an AddItemButtonTile. If it doesn't exist, I want to add it to the list.
#override
void initState() {
if (!displayedList.listContent.contains(AddItemButtonTile)) {
displayedList.listContent.add(AddItemButtonTile(openTextField));
}
super.initState();
}
This code results in a new AddItemButtonTile being added every time I navigate away and return to the page. Why is this If statement returning true?
Try:
#override
void initState() {
if (!displayedList.listContent.any((item) => item is AddItemButtonTile)) {
displayedList.listContent.add(AddItemButtonTile(openTextField));
}
super.initState();
}