I'm using a StreamBuilder widget to show the score in real-time (fetching the data from API and then passing it to the stream) but while doing this process, it is throwing up the following error
"A non-null value must be returned since the return type 'Stream' doesn't allow null"
Here is the Code
class Match extends StatefulWidget {
@override
State<Match> createState() => _MatchState();
}
class _MatchState extends State<Match> {
getCricketScoreApi() async {
var url = Uri.parse(api_url);
var response = await get(url);
if(response.statusCode == 200){
final score = jsonDecode(response.body);
return score['cricket_score'];
} else {
return print('Something went wrong');
}
}
Stream streamScore() {
return Stream.periodic(Duration(seconds: 1), (Timer) => getCricketScoreApi()); // Calling method after every 1 second
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[200],
body: StreamBuilder(
stream: streamScore(),
builder: (context, snapshot){
var cricket_score_api = snapshot.data.toString();
if(snapshot.hasData){
return Center(
child: Text(cricket_score_api, style: TextStyle(color: Colors.grey, fontSize: 25.0)), // Error: Instance of Future
);
} else {
return Text('Null');
}
}
),
);
}
}
CodePudding user response:
So as you say, the original error came from not returning a value.
The current error is even simpler, you ARE returning a value, but that value is, an instance of Future
, so when you call snapshot.data.toString();
, you get the literal text instance of Future
I came up with two ways of fixing the issue, here they are now:
1. Make your stream function an async* function:
Stream streamScore() async* {
while (true) {
await Future.delayed(Duration(seconds: 1));
yield await getCricketScoreApi();
}
}
async*
functions work like async
functions, but instead of returning a future, they return a stream immediately and add values to the stream progressively using the yield
keyword.
The one thing I don't love about the approach above is the usage of while (true)
, it seems unsafe.
2. Deal with the future
Stream<Future> streamScore() {
...
}
...
body: StreamBuilder<Future>(
stream: streamScore(),
builder: (context, snapshot){
if(snapshot.hasData) {
return FutureBuilder(
future: snapshot.data!
builder: (context, snapshot1) {
if (snapshot.hasData) {
return Center(child: Text(snapshot1.data!.toString()));
}
return CircularProgressIndicator();
}
);
} else {
return Text('Null');
}
}
),
Hopefully one of the above solutions fix the new issue?