Issue
In my application user can have multiple home and multiple rooms for each home. On top of my application I have dropdown box which im trying to set default value to selectedHome by user. Below that dropdown box I am showing the rooms in the home selected by user. In firebase I have rooms collection under each home. I'm getting the selected home data from firebase too. Also to show the rooms in selected home i need to query by home name. I have two FutureBuilder as you can see code below. One of them to get the selectedHome data from firebase and other for the getting the rooms in that home from firebase. As I said before to get the rooms in selected home I need to query by name of the home so I have a parameter which is the value of dropdownbox. In my code the problem is getting the rooms part is working before I get the selectedHome data from firebase and assign it to dropdown value. In this case I'm getting "Null check operator used on a null value".
Basicly the question is how can i assign value from future to variable before screen gets build.
Here you can see the code for getting selected home data from firebase;
Future<String> selectedHome() async {
return await database.selectedHome();
}
Future<String> selectedHome() async {
DocumentSnapshot docS =
await firestore.collection("users").doc(auth.currentUser()).get();
String selectedHome = (docS.data() as Map)["selectedHome"];
return selectedHome;
}
Here you can see the code for getting room data based on selectedHome from firebase;
Future<List<Map>> deviceAndRoomInfo() async {
return database.numberOfRooms(_dropdownValue!);
}
Future<List<Map>> numberOfRooms(String selectedHome) async {
List<Map> prodsList = [];
final snapshot = await firestore
.collection("users")
.doc(auth.currentUser())
.collection("homes")
.doc(selectedHome)
.collection("rooms")
.get();
List listOfRooms = snapshot.docs;
for (int a = 1; a <= listOfRooms.length; a++) {
var productsInRoom = await firestore
.collection("users")
.doc(auth.currentUser())
.collection("homes")
.doc(selectedHome)
.collection("rooms")
.doc(listOfRooms[a - 1]["roomName"])
.collection("products")
.get();
List prodList = productsInRoom.docs
.map((e) => DeviceModel.fromMap(e.data()))
.toList();
Map qq = {
"roomName": listOfRooms[a - 1]["roomName"],
"deviceInfo": prodList
};
prodsList.add(qq);
}
return prodsList;
}
Here you can see the code for screen contains 2 future builder that i told;
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:shelly_ess_production/constants.dart';
import 'package:shelly_ess_production/helper_widgets/loading_widget.dart';
import 'package:shelly_ess_production/screens/home_screen/components/circle_room_data.dart';
import 'package:shelly_ess_production/screens/home_screen/components/device_in_room_card.dart';
import 'package:shelly_ess_production/screens/home_screen/provider/home_screen_provider.dart';
import 'package:shelly_ess_production/screens/models/device_model.dart';
import 'package:shelly_ess_production/size_config.dart';
class Body extends StatefulWidget {
const Body({Key? key}) : super(key: key);
@override
State<Body> createState() => _BodyState();
}
class _BodyState extends State<Body> {
@override
Widget build(BuildContext context) {
var providerHelper =
Provider.of<HomeScreenProvider>(context, listen: false);
return SafeArea(
child: Padding(
padding:
EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(0.07)),
child: SingleChildScrollView(
child: Column(
children: [
SizedBox(
height: getProportionateScreenHeight(0.02),
),
Consumer<HomeScreenProvider>(builder: (context, data, child) {
return FutureBuilder<List<String>>(
future: data.getHomesAndSelected(),
builder: (context, snapshot) {
if (snapshot.hasData) {
data.setDropDownValue = snapshot.data![0];
return DropdownButtonHideUnderline(
child: DropdownButton(
iconEnabledColor: kPrimaryColor,
iconDisabledColor: kPrimaryColor,
style: TextStyle(
color: kPrimaryColor,
fontSize: getProportionateScreenHeight(0.05)),
menuMaxHeight: getProportionateScreenHeight(0.4),
borderRadius: BorderRadius.circular(15),
key: UniqueKey(),
value: data.dropdownValue,
isExpanded: true,
icon: const Icon(Icons.arrow_downward),
onChanged: (String? newValue) async {
data.setDropDownValue = newValue;
await data.changeSelectedHome();
},
items: snapshot.data!
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
alignment: Alignment.center,
value: value,
child: Text(value),
);
}).toList(),
),
);
} else {
return Transform.scale(
scale: 0.5,
child: const Center(
child: CircularProgressIndicator(),
),
);
}
});
}),
SizedBox(
height: getProportionateScreenHeight(0.02),
),
SizedBox(
height: getProportionateScreenHeight(0.14),
child: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemCount: 5,
itemBuilder: (context, index) {
return CircleRoomData(
title: "Oda Sayısı",
icon: Icons.meeting_room,
content: "8",
);
}),
),
Consumer<HomeScreenProvider>(builder: (context, data, snapshot) {
return FutureBuilder<List<Map>>(
future: data.deviceAndRoomInfo(data.dropdownValue!),
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
physics: const NeverScrollableScrollPhysics(),
itemCount: snapshot.data!.length,
shrinkWrap: true,
itemBuilder: (context, index) {
return Column(
children: [
Divider(
thickness:
getProportionateScreenHeight(0.002),
),
Text(
snapshot.data![index]["roomName"],
style: TextStyle(
fontWeight: FontWeight.bold,
color: kSecondaryColor,
fontSize:
getProportionateScreenHeight(0.03)),
),
SizedBox(
height: getProportionateScreenHeight(0.01),
),
Text(
"${(snapshot.data![index]["deviceInfo"] as List).length.toString()} Cihaz",
style:
const TextStyle(color: kSecondaryColor),
),
SizedBox(
height: getProportionateScreenHeight(0.02),
),
GridView.builder(
shrinkWrap: true,
physics:
const NeverScrollableScrollPhysics(),
itemCount: (snapshot.data![index]
["deviceInfo"] as List)
.length,
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
),
itemBuilder: (context, indexx) {
print(index);
return DeviceInRoom(
icon: Icons.light,
productName: ((snapshot.data![index]
["deviceInfo"]
as List)[indexx] as DeviceModel)
.deviceName,
);
})
],
);
});
} else {
return const Center(
child: CircularProgressIndicator(),
);
}
});
}
)
],
)),
),
);
}
}
Solution
Am not certain where your error is coming from, but from what I see it maybe as a result of one of your functions returning null and a rendering of your content happens before the data is received.
You could try one of these:
You could declare the return type of your feature as being nullable
for example you are expecting a value of type int
:
Future<int?> xyz(){
......
return .....;
}
Now because your return type is nullable
you wont have an issues as long as the receiving variable is also nullable
.
Alternatively:
Future<int?> xyz(){
......
return ..... ?? 10 /*some default value*/;
}
because you know you result could be null
you could also provide an optional default
value incase your Future
call returns a null value.
Answered By - Tim
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.