How we need work with snapshot and futurebuilder? - flutter

For the moment when i use futurebuilder and snapshot, i do like that :
So in future i set the function with the data. After i test snapshot.connectionState with waiting. What do you think about this way of working, i am not sure it is correct
FutureBuilder(
future: ListLotto,
builder: (BuildContext context, AsyncSnapshot snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return new Center(
child: new CircularProgressIndicator(),);
default:
if (snapshot.hasError) {
return new Center(
child: new Text('Error: ${snapshot.error}'),);
}
else {
List<Lotto_grid> values = snapshot.data;
if (values.isEmpty) {
return Container(

FutureBuilder(
future: myFuture,
initialData: initialValue,//specify it if necessary
builder: (BuildContext context, AsyncSnapshot snapshot) {
switch(snapshot.connectionState){
case ConnectionState.done:
if(snapshot.hasError) {
return myErrorWidget();
} else if(snapshot.hasData) {
return MyDataWidget();
} else{//if snapshot.data == null
return MyOtherWidget();
}
default:
return CircularProgressIndicator();
}
}
)
This one is better as it checks if data is null so you don't get NullPointerException at this line:
List values = snapshot.data;

Related

returning a FutureBuilder as the result of a FutureBuilder Flutter

I'm creating an add friend page in Flutter/Firebase. I used a StreamBuilder to see the changes of the username input. Then I used a FutureBuilder as the result of the StreamBuilder to get my List of User. To verify that the users aren't already in thisUser's friend list, I'm using an other FutureBuilder as the result of the first one. And I still do the same for the friend requests.
It works but I'm pretty sure that not the right way. Could someone explain me how to do that more properly?
StreamBuilder(
stream: controller.usernameStream.stream,
builder: (context, snapshot) {
if (snapshot.hasData) {
String usernameSearched = snapshot.data!;
return FutureBuilder(
future: _userRepo.getUsersStartsByUsername(usernameSearched),
builder: (context, snapshotUsers){
if(snapshotUsers.connectionState == ConnectionState.done){
if (snapshotUsers.hasData){
return controller.futureBuilderFriends(thisFireUser, snapshotUsers);
} else {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Center(child: Text(AppLocalizations.of(context)!.noUsers)),
);
}
}
return Container();
},
);
}
return Container();
},
)
FutureBuilder<List<String>> futureBuilderFriends(User? thisFireUser, AsyncSnapshot<List<U.User>> snapshotUsers) {
return FutureBuilder(
future: _userRepo.getFriendsId(thisFireUser!.uid),
builder: (BuildContext context, AsyncSnapshot<List<String>> snapshotFriends) {
if (snapshotFriends.connectionState == ConnectionState.done) {
if(snapshotFriends.hasData){
return futureBuilderMyFriendRequests(thisFireUser, snapshotFriends.data!, snapshotUsers);
} else {
return futureBuilderMyFriendRequests(thisFireUser, [], snapshotUsers);
}
} else {
return Container();
}
},
);
}
FutureBuilder<List<String>> futureBuilderMyFriendRequests(User thisFireUser, List<String> friends, AsyncSnapshot<List<U.User>> snapshotUsers) {
return FutureBuilder(
future: _userRepo.getFriendRequestsId(thisFireUser.uid),
builder: (BuildContext context, AsyncSnapshot<List<String>> snapshotFriendRequests) {
if (snapshotFriendRequests.connectionState == ConnectionState.done) {
if(snapshotFriendRequests.hasData){
return buildAddFriends(context, snapshotUsers.data!, thisFireUser, friends, snapshotFriendRequests.data!);
} else {
return buildAddFriends(context, snapshotUsers.data!, thisFireUser, friends, []);
}
} else {
return Container();
}
},
);
}
Looks like you are on vanilla architecture. Please make use of bloc or Riverpod and use the transfrom functions and emit the states accordingly

The body might complete normally, causing 'null' to be returned

body: FutureBuilder(
future: determinePosition(),
builder: (context, snapshot) //error here{
if (snapshot.connectionState == ConnectionState.waiting) {
return CircularProgressIndicator();
} else if (snapshot.hasError) {
return Text("Error ");
}else if(snapshot.hasData){
return Column(
children: [
Text(currentAddress),
The body might complete normally, causing 'null' to be returned, but the return type, 'Widget', is a potentially non-nullable type. why it is wrong ? help me
The problem is that you're using else if instead of else. By using else if, you're telling Dart to follow this set of conditions, but what if there's another condition? that won't be handled, and will return null.
To fix the issue, use else instead of else if in the last clause:
FutureBuilder(
future: determinePosition(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return CircularProgressIndicator();
} else if (snapshot.hasError) {
return Text("Error ");
} else {
return Column(
children: [
Text('test'),
],
);
}
})
The potential solution is remove last else if (which is snapshot.hasData) and directly return the the column same as below
body: FutureBuilder(
future: determinePosition(),
builder: (context, snapshot) //error here{
if (snapshot.connectionState == ConnectionState.waiting) {
return CircularProgressIndicator();
} else if (snapshot.hasError) {
return Text("Error ");
}
return Column(
children: [
Text(currentAddress),

Wait a function to be done in ListView

I need to wait my function to be done in a ListView because of a Firestore request. I tried using Future.wait() but it does not work.
FutureBuilder<QuerySnapshot>(
future: FirebaseFirestore.instance
.collection('Statements')
.where('userID',isEqualTo: context.watch<User>().uid)
.get(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot){
if (snapshot.hasError) {return Text("Erreur");}
if (snapshot.connectionState == ConnectionState.waiting) {
return Text("Loading");}
return Expanded(
child:ListView.builder(
itemCount: snapshot.data.docs.length,
itemBuilder: (context, index) {
DocumentSnapshot document = snapshot.data.docs[index];
Future.wait([getStatementData(document)]);
return StatementCard(statement:selectedStatement,
accommodation : relatedAccommodation,
owner : relatedOwner);
},
)
Here is the function called :
Future getStatementData(document) async {
selectedStatement = Statement.fromFirebase(document);
document.data()["accommodation"].get().then((value) {
relatedAccommodation = Accommodation.fromFirebase(value);});
await FirebaseFirestore.instance
.collection('Owners')
.doc(document["ownerList"][0])
.get().then((value) {
print(value.data());
relatedOwner = Owner.fromFirebase(value);
});
}
Should I use another future builder ?
You should do it like this by returning another Future Builder inside :
ListView.builder(
itemCount: snapshot.data.docs.length,
itemBuilder: (context, index) {
DocumentSnapshot document = snapshot.data.docs[index];
return FutureBuilder(
future: getStatementData(document) ,
builder: (context, snapshot) {
return snapshot.connectionState == ConnectionState.done
? StatementCard(statement:selectedStatement,
accommodation : relatedAccommodation,
owner : relatedOwner);
: Container();
);
},
)
I think you just missed a simple thing, FutureBuilder also has a connectionstate.done state which you can access. This waits until your future function is Done.
return FutureBuilder(
future: yourFunction,
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
return Center(child: Text('No status',);
break;
case ConnectionState.waiting:
return Center(child: CircularProgressIndicator());
break;
case ConnectionState.done:
return Text('Im done!') // Your listviewbuilder comes here
break;
default:
}
},
),
doc: https://api.flutter.dev/flutter/widgets/FutureBuilder-class.html
example FutureBuilder with ListViewBuilder: https://medium.com/nonstopio/flutter-future-builder-with-list-view-builder-d7212314e8c9
[...]connectionState.done = [future] is not null, and has completed. If the future completed successfully, the [AsyncSnapshot.data] will be set to the value to which the future completed. If it completed with an error, [AsyncSnapshot.hasError] will be true and [AsyncSnapshot.error] will be set to the error object.[...]

How to get the result of a future within the builder method of a FutureBuilder widget?

I have looked all over and cannot seem to find a solution to this problem. I have a Future<bool> = isAuth.
I have a future builder defined as follows:
FutureBuilder(
future: isAuth,
builder(context, snapshot){
if(connectionState == connectionState.done){
// Some Code Here
}
if(connectionState == ConnectionState.waiting){
CircularProgressIndicator()
}
}
My question is, how do I return one widget if isAuth returns true, and another if isAuth returns false? I am displaying a loading spinner while waiting on the result of isAuth, and once I have the result, I want to display one of two forms?
You can access a FutureBuilder's future value with snapshot.data.
Don't forget to check if snapshot.data is defined using snapshot.hasData :
FutureBuilder<bool>(
future: isAuth,
builder: (context, snapshot) {
if(connectionState == connectionState.done){
if (snapshot.hasData){
if (snapshot.data) return TrueWidget();
else return FalseWidget();
// Or with a one-liner :
// return snapshot.data ? TrueWidget() : FalseWidget();
}
}
if(connectionState == ConnectionState.waiting){
return CircularProgressIndicator(); // Don't forget to return a widget in a builder method
}
}
)
new FutureBuilder<bool>(
future: isAuth, // async work getting the call for true of false
builder: (BuildContext context, AsyncSnapshot<bool> snapshot) {
bool value = snapshot.data;
switch (snapshot.connectionState) {
case ConnectionState.waiting: return new Text('Loading....');
default:
if (snapshot.hasError)
return new Text('Error: ${snapshot.error}');
else
return value ?
new Text('sample one'): Text('sample two')
}
},
)

Flutter perfect message when snapshot.data doesn't have data in Future

in this below code i try to show list is empty message when snapshot.hasData is false
body: FutureBuilder(
future: Provider.of<TicketRepliesTableDao>(context).find(ticketId: _ticket.id),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.hasData) {
final List<TicketRepliesTableData> ticketReplies = snapshot.data;
if (ticketReplies.isNotEmpty) {
}
} else {
return _loader(message: 'list is empty');
}
} else
return CircularProgressIndicator();
},
),
but in that i have CircularProgressIndicator() always, in view,even it doesn't have any data and ticketReplies is empty
Update your builder, with this logic.
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.hasData) {
// show your data
return Text(snapshot.data);
} else {
// show list is empty
return Text("List is empty");
}
}
// by default show loading bar
return CircularProgressIndicator();
}