Is there a way to load async data on InitState method?

DartFlutter

Dart Problem Overview


I'm a looking for a way to load async data on InitState method, I need some data before build method runs. I'm using a GoogleAuth code, and I need to execute build method 'till a Stream runs.

My initState method is:

 @override
  void initState () {
    super.initState();
    _googleSignIn.onCurrentUserChanged.listen((GoogleSignInAccount account)     {
      setState(() {
        _currentUser = account;
      });
    });
    _googleSignIn.signInSilently();
  }

I will appreciate any feedback.

Dart Solutions


Solution 1 - Dart

You can create an async method and call it inside your initState

@override
void initState () {
  super.initState();
  WidgetsBinding.instance.addPostFrameCallback((_){
    _asyncMethod();
  });
        
}

_asyncMethod() async {
  _googleSignIn.onCurrentUserChanged.listen((GoogleSignInAccount account)     {
    setState(() {
      _currentUser = account;
    });
  });
  _googleSignIn.signInSilently();
}

Solution 2 - Dart

As of now using .then notation seems to work:

  // ...
  @override
  initState() {
    super.initState();
    myAsyncFunction
    // as suggested in the comment
    // .whenComplete() {
    // or
      .then((result) {
    print("result: $result");
    setState(() {});
    });
  }
  //...

Solution 3 - Dart

Method 1 : You can use StreamBuilder to do this. This will run the builder method whenever the data in stream changes.

Below is a code snippet from one of my sample projects:

StreamBuilder<List<Content>> _getContentsList(BuildContext context) {
    final BlocProvider blocProvider = BlocProvider.of(context);
    int page = 1;
    return StreamBuilder<List<Content>>(
        stream: blocProvider.contentBloc.contents,
        initialData: [],
        builder: (context, snapshot) {
          if (snapshot.data.isNotEmpty) {
            return ListView.builder(itemBuilder: (context, index) {
              if (index < snapshot.data.length) {
                return ContentBox(content: snapshot.data.elementAt(index));
              } else if (index / 5 == page) {
                page++;
                blocProvider.contentBloc.index.add(index);
              }
            });
          } else {
            return Center(
              child: CircularProgressIndicator(),
            );
          }
        });
  }

In the above code StreamBuilder listens for any change in contents, initially its an empty array and shows the CircularProgressIndicator. Once I make API call the data fetched is added to contents array, which will run the builder method.

When the user scrolls down, more content is fetched and added to contents array which will again run builder method.

In your case only initial loading will be required. But this provides you an option to display something else on the screen till the data is fetched.

Hope this is helpful.

EDIT:

In your case I am guessing it will look something like shown below:

StreamBuilder<List<Content>>(
        stream: account, // stream data to listen for change
        builder: (context, snapshot) {
			if(account != null) {
				return _googleSignIn.signInSilently();
			} else {
				// show loader or animation
			}
        });

Method 2: Another method would be to create an async method and call it from you initState() method like shown below:

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

  void asyncMethod() async {
    await asyncCall1();
    await asyncCall2();
	// ....
  }

Solution 4 - Dart

Create anonymous function inside initState like this:

@override
void initState() {
  super.initState();
  
  // Create anonymous function:
  () async {
    await _performYourTask();
    setState(() {
     // Update your UI with the desired changes. 
    });
  } ();
}

Solution 5 - Dart

Previous Answer!!

You can set a Boolean value like loaded and set it to true in your listen function and make your build function return your data when loaded is set to true otherwise just throw a CircularProgressIndicator

Edited -- I would not suggest calling setState in a method you call in initState. If the widget is not mounted while the setState is called (as the async operation completes) an error will be reported. I suggest you use a package after_layout

Take a look at this answer for better understanding setState in initState : https://stackoverflow.com/a/53373017/9206337

This post will give you an idea to know when the app finishes the build method. So that you can wait for your async method to setState after widget is mounted : https://stackoverflow.com/a/51273797/9206337

Solution 6 - Dart

  @override
  void initState() {
    super.initState();
    asyncInitState(); // async is not allowed on initState() directly
  }

  void asyncInitState() async {
    await yourAsyncCalls();
  }

Solution 7 - Dart

You can create an async method and call it inside your initState

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

    asyncMethod(); ///initiate your method here
  }

Future<void> asyncMethod async{
 
 await ///write your method body here
}

Solution 8 - Dart

Per documentation at https://pub.dev/packages/provider

initState() {
  super.initState();
  Future.microtask(() =>
    context.read<MyNotifier>(context).fetchSomething(someValue);
  );
}

Solution 9 - Dart

Sample code:

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

    asyncOperation().then((val) {
      setState(() {});
      print("success");
    }).catchError((error, stackTrace) {
      print("outer: $error");
    });

//or

    asyncOperation().whenComplete(() {
      setState(() {});
      print("success");
    }).catchError((error, stackTrace) {
      print("outer: $error");
    });
  }

  Future<void> asyncOperation() async {
    await ... ;
  }

Solution 10 - Dart

initState() and build cannot be async; but in these, you can call a function that is async without waiting for that function.

Solution 11 - Dart

How about this?

@override
void initState() {
 //you are not allowed to add async modifier to initState
 Future.delayed(Duration.zero,() async {
  //your async 'await' codes goes here
 });
 super.initState();
}

Solution 12 - Dart

@override
  void initState() {
    super.initState();
     _userStorage.getCurrentUser().then((user) {
      setState(() {
        if (user.isAuthenticated) {
          Timer.run(() {
            redirectTo();
          });
        }
      });
    });
  }

 void redirectTo() {
    Navigator.push(context,
        MaterialPageRoute(builder: (BuildContext context) => new ShopOrders()));
  }

Solution 13 - Dart

As loading or waiting for initial state is a (generally) aone off event FutureBuilder would seem to be a good option as it blocks once on an async method; where the async method could be the loading of json config, login etc. There is an post on it [here] in stack.(https://stackoverflow.com/questions/50844519/flutter-streambuilder-vs-futurebuilder)

Solution 14 - Dart

I have used timer in initState

Timer timer;

@override
void initState() {
  super.initState();
  timer = new Timer.periodic(new Duration(seconds: 1), (Timer timer) async {
      await this.getUserVerificationInfo();
  });
}

@override
void dispose() {
    super.dispose();
    timer.cancel();
}

getUserVerificationInfo() async {
   await someAsyncFunc();
   timer.cancle();
}

Solution 15 - Dart

Sweet and Short:

(() async {
      await your_method();
      setState(() {....anything here});
 })();

Solution 16 - Dart

I came here because I needed to fetch some files from FTP on program start. My project is a flutter desktop application. The main thread download the last file added to the FTP server, decrypts it and displays the encrypted content, this method is called from initState(). I wanted to have all the other files downloaded in background after the GUI shows up.

None of the above mentioned methods worked. Constructing an Isolate is relatively complex.

The easy way was to use the "compute" method:

  1. move the method downloading all files from the FTP out of the class.
  2. make it an int function with an int parameter (I do not use the int parameter or the result)
  3. call it from the initState() method

In that way, the GUI shows and the program downloads the files in background.

  void initState() {
    super.initState();
    _retrieveFileList(); // this gets the first file and displays it
    compute(_backgroundDownloader, 0); // this gets all the other files so that they are available in the local directory
  }

int _backgroundDownloader(int value) {
  var i = 0;
  new Directory('data').createSync();
  FTPClient ftpClient = FTPClient('www.guckguck.de',
      user: 'maxmusterman', pass: 'maxmusterpasswort');
  try {
    ftpClient.connect();
    var directoryContent = ftpClient.listDirectoryContent();
	// .. here, fileNames list is reconstructed from the directoryContent

    for (i = 0; i < fileNames.length; i++) {
      var dirName = "";
      if (Platform.isLinux)
        dirName = 'data/';
      else
        dirName = r'data\';
      var filePath = dirName + fileNames[i];
      var myDataFile = new File(filePath);
      if (!myDataFile.existsSync())
        ftpClient.downloadFile(fileNames[i], File(filePath));
    }
  } catch (err) {
    throw (err);
  } finally {
    ftpClient.disconnect();
  }
  return i;

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJoseph ArriazaView Question on Stackoverflow
Solution 1 - DartdiegoveloperView Answer on Stackoverflow
Solution 2 - DartNaeView Answer on Stackoverflow
Solution 3 - DartThanthuView Answer on Stackoverflow
Solution 4 - DartiDecodeView Answer on Stackoverflow
Solution 5 - DartFardeen KhanView Answer on Stackoverflow
Solution 6 - DartGorgesView Answer on Stackoverflow
Solution 7 - DartSupun DewapriyaView Answer on Stackoverflow
Solution 8 - DartGeorge ObregonView Answer on Stackoverflow
Solution 9 - Dartlive-loveView Answer on Stackoverflow
Solution 10 - DartMuhammad Umair SaqibView Answer on Stackoverflow
Solution 11 - DartAmeer Hamza TariqView Answer on Stackoverflow
Solution 12 - DartAathiView Answer on Stackoverflow
Solution 13 - DartMark ParrisView Answer on Stackoverflow
Solution 14 - DartSaad AhmedView Answer on Stackoverflow
Solution 15 - DartAKASH MATHWANIView Answer on Stackoverflow
Solution 16 - DartamirzolalView Answer on Stackoverflow