Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

This Overlay widget cannot be marked as needing to build because the framework is already in the process of building widgets

Tags:

flutter

I have got follow app:

class MyAppState extends State<MyApp>
{
  TenderApiProvider _tenderApiProvider = TenderApiProvider();

  Future init() async {
     await _tenderApiProvider.getToken();  
  }
  MyAppState()
  {
    init();
  }

  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        ChangeNotifierProvider(builder: (_) => _tenderApiProvider),
      ],
      child: MaterialApp(
        title: "My App",
        routes: {
          '/': (context) => HomePage(),
          '/splash-screen': (context) => SplashScreen(),
          '/result_table': (context) => ResultDataTable(),
        }

      ),
    );
  }

}

I need to draw firstly SplashScreen current code show at start HomePage.

In splash-screen I need to switch to HomePage after all data loaded. Here it's code:

  Widget build(BuildContext context) {
    TenderApiProvider apiProv = Provider.of<TenderApiProvider>(context);
    return StreamBuilder(
        stream: apiProv.resultController,
        builder: (BuildContext context, AsyncSnapshot snapshot) {   
        //...
        if(apiProv.apiKeyLoadingState ==  ApiKeyLoadingState.Done && apiProv.regionsLoadingState == RegionsLoadingState.Done)
        {
         Navigator.of(context).pushNamed("/"); // Should it be placed in Build??
        }
        });
    }

Could you help me and show to to draw at app start SplashScreen and then switch from it to HomePage?

like image 789
Dmitry Bubnenkov Avatar asked Aug 22 '19 08:08

Dmitry Bubnenkov


1 Answers

You will need to wrap your SplashScreen() inside a StatefulWidget so you can fetch your data in initState(). It is important to wrap fetch() logic inside a SchedulerBinding.instance.addPostFrameCallback() to access the BuildContext inside initState(). Also, that way, you avoid conflicts with RenderObjects that get destoryed while they are actually build.

Following a complete minimal example. EDIT: You cant use await in initState({}).

class App extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Wrapper(),
    );
  }
}


class Wrapper extends StatefulWidget {
  @override
  _WrapperState createState() => _WrapperState();
}

class _WrapperState extends State<Wrapper> {

  @override
  void initState() {
    super.initState();
    SchedulerBinding.instance.addPostFrameCallback((_) {
      _loadDataAndNavigate()
    });
  }

  _loadDataAndNavigate() async {
    // fetch data | await this.service.fetch(x,y)
    Navigator.of(context).pushNamed('/');
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SplashScreen(),
    );
  }
}
like image 86
Daniel Eberl Avatar answered Dec 11 '22 18:12

Daniel Eberl