Flutter stream does not update global variable - flutter

On my firebase server i have a document which contains a bool field with the value "true"
I created a stream to listen for this value:
final CollectionReference _ref = FirebaseFirestore.instance.collection('collection');
Stream? getValue;
bool value = false;//Global variable
void initState() {
super.initState();
getValue = _ref.doc().collection("list").doc().snapshots();
getValue.forEach((element){
value = element["value"];
print(value);//Shows the correct value if it changes
});
}
//Somewhere else in the code but in the same class
print(value);//Shows always false even if i change it on firebase to true and i don`t know why?
Let meh know if you needmore information, Thank you!

To update your value in a StatefulWidget, you should wrap with a setState.
_ref.doc().collection("list").doc().snapshots().listen((element) {
if (!mounted) {
return;
}
setState(() {
value = element["value"];
});
});

Related

SharedPrefrences delay before initializing - Flutter

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

How to change provider state within itself?

Minimal reproducible code:
final provider = StateProvider<bool>((ref) {
Timer? _timer;
ref.listenSelf((_, flag) {
if (!flag) {
_timer = Timer(Duration(seconds: 5), () {
ref.read(this).state = true;
});
}
});
// ... disposing timer, etc.
return true;
});
The above provider returns true initially, and I change that value to false in a widget and 5s after that, I want to change this value back to true. I'm using listenSelf but I'm not able to do it.
Note:
I don't want to use StateNotifier with StateNotifierProvider.
The ref of a provider generally exposes a way to modify itself.
In the case of StateProvider, you can do Ref.controller to obtain the StateController
You can therefore do ref.controller.state = true

Flutter :: change value in initialstate in statefull widget from future list

If I have statefull widget with initial satate variable called value ,Like this :
#override
void initState() {
thisDayActivity = dataBase.getDetails(widget.courseId, widget.actId);
value = 0.0;
super.initState();
}
thisDayActivity is future list comming from sqflite database, I want check if the list is empty the value variable equal to 0,else value equale some data in future list.
I tride this but don't work :
#override
void initState() {
thisDayActivity = dataBase.getDetails(widget.courseId, widget.actId);
if (thisDayActivity == []) {
value = 0.0;
} else {
value = thisDayActivity[0]['digree'].toDouble();
}
super.initState();
}
How can I solve this?
your method is not working since you are reading a value from a future function, what you need to do is to use the then method to achieve your goal like this:
#override
void initState() {
dataBase.getDetails(widget.courseId, widget.actId)
.then((thisDayActivity) {
if (thisDayActivity == []) {
value = 0.0;
} else {
value = thisDayActivity[0]['digree'].toDouble();
}
});
super.initState();
}

OnStateChanged Method in Flutter

In Flutter, is there a method like onStateChanged which is called when the state of the page changes?
setState(() {
widget._loadCompleted = true;
widget._loading = false;
});
I'm trying to set the two bool values in setState() method. I'm setting states for several other reasons. So I want to know if the last state change was for this particular reason.
As Günter mentioned, there is no such thing like onStateChanged(). You have to deal it in build() method.
If I got you right, you can use like this:
class _MyAppState extends State<MyApp> {
bool myFlag = false; // initially set to false
void _doYourWork() {
setState(() => myFlag = true); // set to true here
}
#override
Widget build(BuildContext context) {
if (myFlag) {
// setState() just got called
} else {
// we are building fresh for the first time.
}
myFlag = false;
return yourWidget();
}
}
After this build() will receive myFlag value to true and it can then set to false again. So, you can do this trick.

Can't archive single data in init state from cloud firestore

I want archive a number from cloud firestore in init state ..below is my code how am trying to archive but it not working ..can anyone tell me how to do that ........
int _prvScore ;
// #protected
// #mustCallSuper
// void initState() {
// _prvScore = 23.toInt();
// }
#override
void initState() {
var month = new DateTime.now().month;
final DocumentReference documentReference =
Firestore.instance.collection('quiz').document('$month')
.collection('1')
.document(username);
subscription =
documentReference.snapshots().listen((datasnapshot) {
if (datasnapshot.data.containsKey("total score")) {
_prvScore = datasnapshot.data['total score'].toInt();
}
});
}
You need to call setState(...) to cause a rebuild.
If you execute async code, the result will not yet be available when the function is completed and build() already executed.
Async code is only executed eventually later.
Changing
_prvScore = datasnapshot.data['total score'].toInt();
to
setState(() => _prvScore = datasnapshot.data['total score'].toInt());
should fix it.
You need to ensure build() doesn't cause an error when _prvScore is still null because no data arrived yet from Firebase.