When the user sign up he type some information then the app navigates to the main screen, the first time I always get LateInitializationError but when I login again to the account no errors, And if I opened on the main screen with the same account also no errors.
class MainScreen extends StatefulWidget {
MainScreen({
Key? key,
}) : super(key: key);
@override
_MainScreenState createState() => _MainScreenState();
}
class _MainScreenState extends State<MainScreen> {
String? userID;
late int age;
late int weight;
late int height;
late int bfp;
late String gender;
late String ac;
late String gl;
late String disease;
late var amr;
late double carb;
late double protein;
late double fats;
late double saturatedFats;
late double vitaminB12;
late double vitaminC;
late double iron;
late double calcium;
late double vitaminD;
late var bmi;
late var breakfast;
late var lunch;
late var dinner;
late Future<void> _userDataFuture;
User? user = FirebaseAuth.instance.currentUser;
List<dynamic> _food = [];
List<Map<String, dynamic>> _mealPlans = [];
@override
void initState() {
super.initState();
_userDataFuture = _initializeData();
}
Future<void> _initializeData() async {
// To initialize user's data before executing functions
await getUserData();
await readJson();
// Initialize other variables
amr = await CaloriesUtils.calculateAMR(
gender: gender,
age: age,
weight: weight,
height: height,
bfp: bfp,
ac: ac,
gl: gl,
);
// Calculate nutrition values
Map<String, double> nutrition = await calculateNutri();
carb = nutrition['carb'] ?? 0;
protein = nutrition['protein'] ?? 0;
fats = nutrition['fats'] ?? 0;
Map<String, double> diseases = await diseasesControl();
saturatedFats = diseases['saturatedFats'] ?? 0;
vitaminB12 = diseases['vitaminB12'] ?? 0;
vitaminC = diseases['vitaminC'] ?? 0;
iron = diseases['iron'] ?? 0;
calcium = diseases['calcium'] ?? 0;
vitaminD = diseases['vitaminD'] ?? 0;
await computeMealPlans();
}
Map<String, double> calculateNutri() {
bmi = weight / pow((height / 100), 2);
Map<String, double> nutrition = NutriUtils.calculateNutri(
age: age,
bmi: bmi,
amr: amr,
ac: ac,
gl: gl,
);
return nutrition;
}
Map<String, double> diseasesControl() {
Map<String, double> diseases = DiseasesUtils.diseasesControl(
amr: amr, weight: weight, gender: gender, age: age, diseases: disease);
return diseases;
}
Future getUserData() async {
try {
final querySnapshot = await FirebaseFirestore.instance
.collection('users')
.where("email", isEqualTo: user?.email)
.get();
if (querySnapshot.docs.isNotEmpty) {
var userData = querySnapshot.docs[0].data();
setState(() {
userID = querySnapshot.docs.first.id;
age = userData['age'].toInt();
gender = userData['gender'];
height = userData['height'].toInt();
weight = userData['weight'].toInt();
disease = userData['disease'];
gl = userData['goalWeight'];
ac = userData['baseLineActivityLevel'];
if (userData['bfp'] != null) {
bfp = userData['bfp'];
} else {
bfp = 0;
}
});
} else {
print('User not found for email: ${user?.email}');
}
} catch (e) {
print('Error fetching user data: $e');
}
}
Future<void> readJson() async {
final String response = await rootBundle.loadString('assets/food.json');
final data = await json.decode(response);
setState(() {
_food = data["food"];
});
}
computeMealPlans() {
CalculateFood.computeMealPlans(
food: _food,
targetProtein: protein,
targetCarb: carb,
targetFats: fats,
diseases: disease,
callback: (List<Map<String, dynamic>> result) {
setState(() {
_mealPlans = result;
});
},
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder<void>(
future: _userDataFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
// Display a loading indicator while waiting for the data
return Center(
child: CircularProgressIndicator(),
);
} else if (snapshot.hasError) {
return Center(
child: Text('Error while loading data: ' + snapshot.error.toString()),
);
} else if (user == null) {
return Center(
child: Text('No user Found'),
);
}
return StreamBuilder(
stream: FirebaseFirestore.instance
.collection('users')
.doc(userID)
.snapshots(),
builder: (context, snapshot) {
return Container (
// Rest of UI .....
)
},
);
}),
);
}
}
I tried to sign up a new user after I type my information and the app navigates me to main or home screen the I got I/flutter (23136): Error fetching user data: type 'Null' is not a subtype of type 'String'
form that try block
Future getUserData() async {
try {
final querySnapshot = await FirebaseFirestore.instance
.collection('users')
.where("email", isEqualTo: user?.email)
.get();
if (querySnapshot.docs.isNotEmpty) {
var userData = querySnapshot.docs[0].data();
setState(() {
userID = querySnapshot.docs.first.id;
age = userData['age'].toInt();
gender = userData['gender'];
height = userData['height'].toInt();
weight = userData['weight'].toInt();
disease = userData['disease'];
gl = userData['goalWeight'];
ac = userData['baseLineActivityLevel'];
if (userData['bfp'] != null) {
bfp = userData['bfp'];
} else {
bfp = 0;
}
});
} else {
print('User not found for email: ${user?.email}');
}
} catch (e) {
print('Error fetching user data: $e');
}
}
and the snapshot has error while the screen displays Error while loading data: LateInitializationError: Field ‘bfp’ has not been initialized. from the future builder
2
Answers
Change the
late
keyword and assign a default value to each variable like thisor make the variables null-able like this
and then handle the null value when using e.g
// Inside the FutureBuilder
return StreamBuilder(
stream: FirebaseFirestore.instance
.collection(‘users’)
.doc(userID)
.snapshots(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(),
);
} else if (snapshot.hasError) {
return Center(
child: Text(‘Error while loading data: ${snapshot.error.toString()}’),
);
} else if (user == null || age == null || weight == null || height == null) {
return Center(
child: Text(‘User data not initialized yet’),
);
}
},
);