Reputation: 5922
I am trying to use snackbar on my future builder to shows error.So after making my future method instance on initState method:
Future<DetailModel> futureDetail;
...
@override
void initState() {
futureDetail =
DetailProvider().detailProvider(widget.id);
super.initState();
}
In futureBuilder i use like below:
Center(
child: SingleChildScrollView(
child: FutureBuilder(
future: futureDetail,
builder:
(context, AsyncSnapshot<DetailProductModel> snapshot) {
if (!snapshot.hasError ||
snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(),
);
}
if (snapshot.hasData && snapshot.data.data != null) {
return Container();
}
if (snapshot.hasError &&
snapshot.error != null &&
snapshot.data == null) {
WidgetsBinding.instance.addPostFrameCallback((_) =>
showSnackbar(snapshot.error.toString(), context));
return Container();
} else {
return Center(
child: Text('failed to load'),
);
}
},
),
),
),
detailProvider
method calls http service and in my example i throw SocketException
to get error on builder and show snackbar.
I know future builder is for showing a widget per state but i want to show snakbar.
But builder is called twice and snackbar shows twice an error?
I checked that this three conditions are the same snapshot.hasError and snapshot.error != null and snapshot.data == null
in twice build . How could i prevent showing twice snakbar?
Upvotes: 0
Views: 1766
Reputation: 5608
Update: There was a problem with the code that I shared. Please, check this out.
First of all, always create your SnackBar outside of the FutureBuilder because FutureBuilder is constantly called, so it causes an infinite loop. What you can do is to use catchError. You can still check whether or not there is an active SnackBar before create a new one by using the variable we already declared.
You will see that SnackBar will show up only once even though I called it thrice when you run the code below.
Apply the same way to update your own code:
class App extends StatefulWidget {
@override
_AppState createState() => _AppState();
}
class _AppState extends State<App> {
bool snackBarActive = false;
Future<String> futureDetail;
@override
void initState() {
futureDetail = Future<String>.error('An error Occurred').catchError((errText) {
showSnackBar(errText);
showSnackBar(errText);
showSnackBar(errText);
});
super.initState();
}
void showSnackBar(String errText) {
if (!snackBarActive) {
setState(() {
snackBarActive = true;
});
WidgetsBinding.instance.addPostFrameCallback((_) => Scaffold.of(context)
.showSnackBar(SnackBar(
content: Text(errText),
))
.closed
.whenComplete(() {
setState(() {
snackBarActive = false;
});
}));
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: SingleChildScrollView(
child: FutureBuilder(
future: futureDetail,
builder: (context, AsyncSnapshot<String> snapshot) {
if (!snapshot.hasError &&
snapshot.hasData &&
snapshot.data != null) {
return Container();
} else {
return Center(
child: Text('failed to load'),
);
}
},
),
),
),
);
}
}
Upvotes: 1