Async-await skips method and continues with the rest of the code, which results in an error code because my variable is not assigned with the value result of my method.
I have been trying multiple methods to accomplish my goal but without success. I have tried converting every ".then" into "Async-Await", make my void method a "Future" method, invoke method within InitState. Futurebuilder wouldnt be a solution as I am not trying to build anything with it.
The code seems to skip after
"await _firestore.collection(‘auth_user’).doc(userid).get();" it goes out and continues at the Widget build. Therefore companyid seems to be null as its not finished yet.
My Screen
class Chatroom extends StatefulWidget {
const Chatroom({super.key});
@override
_ChatroomState createState() => _ChatroomState();
}
class _ChatroomState extends State<Chatroom> {
final userservice = UserService();
final chatservice = ChatService();
String? companyid = '';
@override
void initState() {
super.initState();
getUser();
}
Future<void> getUser() async {
try {
final cpid = await userservice.getCompanyId();
setState(() {
companyid = cpid;
});
} catch (e) {}
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(children: [
ElevatedButton(
child: const Text("test"),
onPressed: () {},
),
Expanded(child: _buildUserList()),
]),
);
}
Widget _buildUserList() {
return StreamBuilder(
stream: chatservice.getChats(companyid ?? ''),
builder: (context, snapshot) {
if (snapshot.hasError) {
return const Text('error');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return const Text('loading..');
}
return ListView(
children: snapshot.data!.docs
.map((document) => _userCard(document))
.toList(),
);
},
);
}
Widget _userCard(DocumentSnapshot doc) {
Map<String, dynamic> data = doc.data() as Map<String, dynamic>;
return Column(children: [
Text(data['name'] ?? 'Anonymous:${doc.id}'),
]);
}
}
Service where I use method from
final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;
final FirebaseFirestore _firestore = FirebaseFirestore.instance;
Future<String> getCompanyId() async {
try {
String userid = _firebaseAuth.currentUser!.uid;
DocumentSnapshot doc =
await _firestore.collection('auth_user').doc(userid).get();
final data = doc.data() as Map<String, dynamic>;
String companyid = data['companyId'];
return companyid;
} on FirebaseAuthException catch (e) {
throw Exception(e.code);
} on FirebaseException catch (e) {
throw Exception(e.code);
}
}
>Solution :
This is the expected behavior. The widget is always going to build as soon as its added to the widget tree.
You can solve this by adding a loading state and showing a CircularProgressIndicator while it is true:
// In your state
bool loading = true;
// Update loading after the user is loaded
Future<void> getUser() async {
try {
final cpid = await userservice.getCompanyId();
setState(() {
companyid = cpid;
loading = false; // Here
});
} catch (e) {}
}
In your widget, just check for this loading flag and only render the full widget when it’s false.