Dmitry Bubnenkov
Dmitry Bubnenkov

Reputation: 9859

How to add delay inside StreamBuilder before switching to new Widget?

I have got StreamBuilder. I am trying to do progress indicator with it. Like:

Loading token DONE
Loading regions DONE
Loading industry DONE

After the last item ("Loading industry DONE") and before switching to HomePage I would like to add small delay. But I can't understand how to do it. I tried to use Future.delayed and Timer, but with them switching to HomePage do not happen. Without Delay/Timer switching works, but I need delay before it.

Here is my code:

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter/semantics.dart';
import 'package:provider/provider.dart';
import 'main.dart';

class SplashScreen extends StatefulWidget {
  SplashScreenState createState() => SplashScreenState();
}

class SplashScreenState extends State<SplashScreen> {
  String tokenLoadingState = '';
  String regionsLoadingState = '';
  String industryLoadingState = '';
  TenderApiProvider apiProv;

  @override
  Widget build(BuildContext context) {
    apiProv = Provider.of<TenderApiProvider>(context);
    return StreamBuilder(
        stream: apiProv.resultController,
        builder: (BuildContext context, AsyncSnapshot snapshot) {
          TenderApiProvider apiProv = Provider.of<TenderApiProvider>(context);

          if (snapshot.data is ApiKeyLoadingState) {
            switch (snapshot.data) {
              case ApiKeyLoadingState.Progress:
                tokenLoadingState = "Loading";
                break;
              case ApiKeyLoadingState.Done:
                tokenLoadingState = "Done";
                break;
              case ApiKeyLoadingState.Error:
                tokenLoadingState = "Error";
                break;
              default:
                return Text("Unknown");
            }
          } else if (snapshot.data is RegionsLoadingState) {
            switch (snapshot.data) {
              case RegionsLoadingState.Progress:
                regionsLoadingState = "Loading";
                break;
              case RegionsLoadingState.Done:
                regionsLoadingState = "Done";
                break;
              case RegionsLoadingState.Error:
                regionsLoadingState = "Error";
                break;
              default:
                return Text("Unknown");
            }
          } else if (snapshot.data is IndustryLoadingState) {
            switch (snapshot.data) {
              case IndustryLoadingState.Progress:
                industryLoadingState = "Loading";
                break;
              case IndustryLoadingState.Done:
                industryLoadingState = "Done";
                break;
              case IndustryLoadingState.Error:
                industryLoadingState = "Error";
                break;
              default:
                return Text("Unknown");
            }

            if (apiProv.apiKeyLoadingState == ApiKeyLoadingState.Done &&
                apiProv.regionsLoadingState == RegionsLoadingState.Done &&
                apiProv.industryLoadingState == IndustryLoadingState.Done) {

              Future.delayed(Duration(milliseconds: 1000)).then(
                  (_) => HomePage() // I need delay before switching to HomePage
              );

            }
          }

          return Scaffold(
              appBar: AppBar(),
              body: Center(
                  child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: <Widget>[
                  Text(
                    "Loading token: $tokenLoadingState",
                    textScaleFactor: 2,
                  ),
                  Text(
                    "Loading regions: $regionsLoadingState",
                    textScaleFactor: 2,
                  ),
                  Text(
                    "Loading industry: $industryLoadingState",
                    textScaleFactor: 2,
                  ),
                ],
              )));
        });
  }
}

Upvotes: 0

Views: 3327

Answers (2)

Daniel Eberl
Daniel Eberl

Reputation: 1424

You need to move you logic outside of the build method. The build method in flutter must not have a delay, else your UI would lag very heavy.

For your usecase, StreamBuilder might not fit. It fits for dynamically displaying content depending of the state of your stream. It tho is not suitable for Routing or Navigation, as this would break the build process of the widget. That means, you have to manually subscribe to the stream. Here is an example. I cant test it, because you have many hidden dependencies.

  @override
  void initState() {
    super.initState();

    SchedulerBinding.instance.addPostFrameCallback((_) {
      TenderApiProvider apiProv = Provider.of<TenderApiProvider>(context);
      apiProv.resultController.listen((data) async {
        if (apiProv.apiKeyLoadingState == ApiKeyLoadingState.Done &&
            apiProv.regionsLoadingState == RegionsLoadingState.Done &&
            apiProv.industryLoadingState == IndustryLoadingState.Done) {

          await Future.delayed(Duration(milliseconds: 1000));// I need delay before switching to HomePag
          Navigator.of(context).pushNamed('/home');

        }
      });

    });

  }

As I can sense you are fairly new to flutter, please consider taking one of the existing free video courses available on youtube.

Upvotes: 2

Manjunath Rao
Manjunath Rao

Reputation: 4260

Try:

import 'dart:async';

Timer(const Duration(milliseconds: 1000), () => HomePage());

Upvotes: 0

Related Questions