3

This is my controller.dart file which checks if users is verified or not and then return the page according to the conditions. My question is that why the build widget is executing first before initState() ? I tried to debug this code using breakpoints and noticed that build() widget is running first and then the initState()Why this is happening and how could I fix it ?

This is my code :

class _ControllerState extends State<Controller> {
  late bool auth;
  @override
  Widget build(BuildContext context) {
    return (auth==false) ? Onbording() : IndexPage();
  }

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance!.addPostFrameCallback((_) async {
      await this.checked_if_logged();
    });

  }
  Future<void> checked_if_logged() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    if(prefs.getBool('verified')==true){
      setState(() {
        auth = true;
      });
    }else{
      setState(() {
        auth = false;
      });
    }
  }
}

This is a snapshot of my debug code where the blue line is showing that it runs first before init and because the bool auth is a late type so it throws lateInitializationErrror and after that initState() is called which initializes the auth variable which rebuild the widget and removes the error enter image description here

Update: I noticed that when I replace the WidgetsBinding.instance!.addPostFrameCallback((_) with just check_if_logged(), the initState() is calling first but before completion of check_if_logged() the build widget executes first which again throws lateInitializationError

Madhav mishra
  • 313
  • 4
  • 20
  • 1
    The addPostFrameCallback is called after first frame is rendered. So in your case init is called then build then the callback. It's working as expected. – danypata Feb 18 '22 at 11:46
  • init is not called first, build widget called first then the init, I updated the question so you may want to read that. Thanks – Madhav mishra Feb 18 '22 at 11:49
  • 1
    I would suggest to print some text like this: one print before WidgetsBinding.instance, one inside the addPostFrameCallback, and one in build method. In your case the ```check_if_logged``` is async called, but that doesn't mean that the init state is called after. The logs will clarify the order of method calls. – danypata Feb 18 '22 at 11:51
  • 1
    Good suggestion, I found that the first print statement above the WidgetBinding.instance executed then it did not waited for completion of WidgetBinding.instance and after that second print executed and then the build method and after all of that it started executing the WidgetBinding.instance . I also noticed that I had to use null check operator(!) while using WidgetBinding.instance!.addPostFrameCallback (there's a null check ) – Madhav mishra Feb 18 '22 at 11:56

1 Answers1

3

I don't know where you got addPostFrameCallback from or what you want to achieve, but this is not the way.

Your problem is, that checked_if_logged is async and there is no way to await an async method in initState. That is by design and there is no way around that.

The proper way to handle this is to use a FutureBuilder widget.

See What is a Future and how do I use it?

nvoigt
  • 75,013
  • 26
  • 93
  • 142