Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Network Request after button click with Flutter

Tags:

flutter

dart

I want to perform a network request (Rest API) against OpenWeatherMap-API after I click on a button in my very first flutter app. Basically I'm following this tutorial: Fetch data from the internet

Therefore I've created the API call, which is following the tutorial and is working like a charm:

class OpenWeatherApi {
    static const _API_KEY = "asdbaklsadfkasdlfkasdjfl";

    Future<CurrentWeather> getCurrentWeather(String location) async {
        final url =
    "https://api.openweathermap.org/data/2.5/weather?q=$location&APPID=$_API_KEY";
        final response = await get(url);
        final responseJson = json.decode(response.body);
         return new CurrentWeather.fromJson(responseJson);
    }
}

I am calling the API within my stateful widget:

class _MyHomePageState extends State<MyHomePage> {
  String _currentWeather = "";

  void _callWeatherApi() {
    var api = new OpenWeatherApi();
    api.getCurrentWeather("Waldershof, Germany").then((weather) {
      setState(() {
        _currentWeather = weather.getTextualRepresentation();
      });
    }, onError: (error) {
      setState(() {
        _currentWeather = error.toString();
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text(widget.title),
      ),
      body: new Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          new TextField(
            decoration: new InputDecoration(
                border: InputBorder.none, hintText: 'Please enter a Location'),
          ),
          new RaisedButton(
            onPressed: () {
              _callWeatherApi();
            },
            child: new Text("Get Weather"),
          ),
          new Text(
            '$_currentWeather',
            style: Theme.of(context).textTheme.display1,
          ),
        ],
      ),
    );
  }
} 

With a click on the RaisedButton, I call my function _callWeatherApi. This function performs the network request and updates my widget afterwards. Basically it's working very well.

But in the example they're using a FutureBuilder-Widget for the network request, which has some nice advantages regarding the state handling (e.g. showing a progress indicator):

new FutureBuilder<Post>(
  future: fetchPost(),
  builder: (context, snapshot) {
    if (snapshot.hasData) {
      return new Text(snapshot.data.title);
    } else if (snapshot.hasError) {
      return new Text("${snapshot.error}");
    }

    // By default, show a loading spinner
    return new CircularProgressIndicator();
  },
);

Unfortunately, I don't know if this FutureBuilder widget can used with a network request that is triggered by a button press.

Because of this, I don't know if my implementation of the network request based on a button press is state-of-the-art or if it can be improved by using e.g. a FutureBuilder or a different widget in Flutter?

Do you have any suggestion for improving my code?

like image 533
Christopher Avatar asked Apr 25 '18 05:04

Christopher


1 Answers

You don't need to write the FutureBuilder. You can achieve without it also.

Here is the another way how you can do it.

Write a function to return a Progressbar or Text in the _MyHomePageState class.

Widget getProperWidget(){
    if(apiCall)
      return new CircularProgressIndicator();
    else
      return new Text(
        '$_currentWeather',
        style: Theme.of(context).textTheme.display1,
      );
  }

Create a local variable to manage the state of API call.

String _currentWeather = "";
bool apiCall = false; // New variable

replace your Text widget in build method with the function and set state apiCall = true.

....
new RaisedButton(
                onPressed: () {
                  setState((){
                    apiCall=true; // Set state like this
                  });
                  _callWeatherApi();
                },
                child: new Text("Get Weather"),
              ),
     getProperWidget()

Hide the progressbar once you receive the response from the request and update your _callWeatherApi function like this:

void _callWeatherApi() {
    var api = new OpenWeatherApi();
    api.getCurrentWeather("Waldershof, Germany").then((weather) {
      setState(() {
        apiCall= false; //Disable Progressbar
        _currentWeather = weather.toString();
      });
    }, onError: (error) {
      setState(() {
        apiCall=false; //Disable Progressbar
        _currentWeather = error.toString();
      });
    });
  }
like image 144
Dhrumil Shah - dhuma1981 Avatar answered Nov 02 '22 02:11

Dhrumil Shah - dhuma1981