Search code examples
flutterflutter-futurebuilder

why futureBuilder callback is not calling after facebook logged in data in flutter?


I am newbie in flutter so please let me know if i am wrong.In my application i have to logged in using facebook so i took a RawMaterialButton and in onPressed function in used following code

child: RawMaterialButton(
                    onPressed: () {
                      FutureBuilder<String>(
                        future:
                            _login(), // function where you call your api
                        builder: (BuildContext context,
                            AsyncSnapshot<String> snapshot) {
                          // AsyncSnapshot<Your object type>
                          print(snapshot);
                          if (snapshot.connectionState ==
                              ConnectionState.done) {
                            print('${snapshot.data}');
                          }
                          if (snapshot.connectionState ==
                              ConnectionState.waiting) {
                            return Center(
                                child: Text('Please wait its loading...'));
                          } else {
                            if (snapshot.hasError)
                              return Center(
                                  child: Text('Error: ${snapshot.error}'));
                            else
                              return Center(
                                  child: new Text(
                                      '${snapshot.data}')); // snapshot.data  :- get your object which is pass from your downloadData() function
                          }
                        },
                      );
                      return CircularProgressIndicator();
                    },

when i press the button its calling the method and i am getting data but after getting those data future building is not updating or showing that data in a Text.here is my data fetch method.

  Future<String> _login() async {
final result = await FacebookAuth.instance.login();
var tokenString;
switch (result.status) {
  case FacebookAuthLoginResponse.ok:
    _printCredentials(result);
    // get the user data
    // final userData = await FacebookAuth.instance.getUserData();
    tokenString = result.accessToken.token;
    break;
  case FacebookAuthLoginResponse.cancelled:
    print("login cancelled");
    tokenString = "User cancelled";
    break;
  default:
    tokenString = "Login failed";
}
return tokenString;
}

For debug purpose i made break point also but its not directing to the asynchronous snapshot condition state checking.I could not find out the reasons. I also check following stack question also.

Why FutureBuilder doesn't get call in Flutter? Flutter FutureBuilder Not Updating


Solution

  • Well, in your onPressed function you are declarating a FutureBuilder and it's definitly wrong. FutureBuilder allows you to make an asynchronous request for a function or method to use the response data to build a widget or another depending of the snapshot value. This happens when you run the widget for the first time or use SetState({}) in a StatefulWidget. But you are joining view code with functional code. This is the way to implement a FutureBuilder:

    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return FutureBuilder(
          future: _login(),
          builder: (context, snapshot) {
            print(snapshot);
            if (snapshot.connectionState == ConnectionState.done) {
              print('${snapshot.data}');
            }
            if (snapshot.connectionState == ConnectionState.waiting) {
              return Center(child: Text('Please wait its loading...'));
              // Or return CircularProgressIndicator();
            } else {
              if (snapshot.hasError)
                return Center(child: Text('Error: ${snapshot.error}'));
              else
                return Center(
                    child: new Text(
                        '${snapshot.data}'));
            }
          },
        );
        // if you return something here, it's dead code
      }
    

    But i would suggest you to implement FutureBuilder in this way:

    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Container(
          alignment: Alignment.center,
          child: FutureBuilder(
            future: _login(),
            builder: (context, snapshot) {
              if (snapshot.hasError) // if it has error
                return Text('Error: ${snapshot.error}');
              if (!snapshot.hasData) {
                // if it's loading
                return Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    Text('Please wait its loading...'),
                    Padding(
                      padding: EdgeInsets.only(top: 20),
                      child: Container(
                        height: 35,
                        width: 35,
                        child: CircularProgressIndicator(),
                      ),
                    ),
                  ],
                );
              } else {
                // if everything success
                print(snapshot.data);
                return Text('${snapshot.data}');
              }
            },
          ),
        );
      }
    

    Finally, what i think you want is use a Provider to create a comunication way between widgets into your login page because you want to change the State of the page/view widget by pressing a button, u could use a StatefulWidget but u should see this tutorial better. and here is the provider documentation.

    Pdst: But, if u don't want to implement provider you could make the _login() request in the button like:

    onPressed: () async {
      String response = await _login();
      Navigator.push(context, MaterialPageRoute(builder: (context) => ResponseWidget(response)));
    }
    

    With navigator.push() you can change the view/page/widget that u have in your screen and show a new widget that could show something deppending the response value.