首页 > 解决方案 > 使用 Flutter 单击按钮后的网络请求

问题描述

在我的第一个颤振应用程序中单击一个按钮后,我想对 OpenWeatherMap-API 执行网络请求(Rest API)。基本上我正在学习本教程:Fetch data from the internet

因此,我创建了 API 调用,它遵循本教程并且工作起来很吸引人:

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);
    }
}

我在有状态的小部件中调用 API:

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,
          ),
        ],
      ),
    );
  }
} 

通过单击RaisedButton,我调用了我的函数_callWeatherApi。此函数执行网络请求并在之后更新我的小部件。基本上它工作得很好。

但在示例中,他们使用FutureBuilder-Widget 进行网络请求,这在状态处理方面具有一些不错的优势(例如,显示进度指示器):

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();
  },
);

不幸的是,我不知道这个FutureBuilder小部件是否可以与按钮按下触发的网络请求一起使用。

正因为如此,我不知道我基于按钮按下的网络请求的实现是否是最先进的,或者是否可以通过FutureBuilder在 Flutter 中使用例如一个或不同的小部件来改进它?

您对改进我的代码有什么建议吗?

标签: dartflutter

解决方案


您不需要编写 FutureBuilder。没有它你也可以实现。

这是另一种方法。

编写一个函数以返回 _MyHomePageState 类中的 Progressbar 或 Text。

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

创建一个局部变量来管理 API 调用的状态。

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

用函数替换 build 方法中的 Text 小部件并设置状态 apiCall = true。

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

收到请求的响应后隐藏进度条并更新 _callWeatherApi 函数,如下所示:

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();
      });
    });
  }

推荐阅读