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?
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();
});
});
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With