Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Flutter: How can I make a stream produce objects in periodic manner?

I have this function that aims at producing a Quote object after every 5 seconds.

Stream<Quote> quotesStream(Realm populatedRealm) async* {
  List<Quote> quotes = populatedRealm.all<Quote>().toList();

  for (Quote aQuote in quotes) {
    // Wait for 5 seconds before yielding the next quote.
    Future<void>.delayed(const Duration(seconds: 5));
    print(aQuote.quote); // Just to see what is going on.
    yield aQuote;
  }
}

It is then called in a StreamBuilder within a StatelessWidget like this.

class HomePage extends StatelessWidget {
  final Quote initialQuote = Quote('Nothing', 'none', '0', 'nothing');
  final String title;

  HomePage({super.key, required this.title});

  // The stream
  final Stream<Quote> newQuotesStream = quotesStream(RealmProvider.realm);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(title)),
      body: Center(
        child: BlocBuilder<QuotesBloc, QuotesState>(
          builder: (context, state) {
            if (state.quotesFetchingStatus == QuotesFetchingStatus.initial) {
              context.read<QuotesBloc>().add(const FetchingQuotes());
              return const CircularProgressIndicator();
            } else if (state.quotesFetchingStatus == QuotesFetchingStatus.success) {
              return StreamBuilder<Quote>(
                stream: newQuotesStream,
                builder: (context, snapshot) {
                  if (snapshot.hasData) {
                    Quote q = snapshot.data!;
                    return QuoteWidget(quote: q);
                  } else {
                    return QuoteWidget(quote: initialQuote);
                  }
                },
              );
            } else {
              return QuoteWidget(quote: initialQuote);
            }
          },
        ),
      ),
    );
  }
}

Apparently, all the quotes are streamed simultaneously; therefore, the QuoteWidget shows only the last quote.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

What am I missing or doing wrong?

>Solution :

Adding await before Future<void>.delayed in quotesStream will fix your issue.

Stream<Quote> quotesStream(Realm populatedRealm) async* {
  List<Quote> quotes = populatedRealm.all<Quote>().toList();

  for (Quote aQuote in quotes) {
    await Future<void>.delayed(const Duration(seconds: 5));
    print(aQuote.quote);
    yield aQuote;
  }
}

Also, as @pskink said you can alternatively use Stream.periodic instead of Future.delayed like this:

Stream<Quote?> quotesStream(Realm populatedRealm) {
  List<Quote> quotes = populatedRealm.all<Quote>().toList();

  return Stream.periodic(const Duration(seconds: 5), (int index) {
    if (index < quotes.length) {
      Quote aQuote = quotes[index];

      print(aQuote.quote);
      return aQuote;
    } else {
      return null;
    }
  }).takeWhile((quote) => quote != null);
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading