【问题标题】:Map<dynamic,dynamic> is null after loading currencies from API从 API 加载货币后 Map<dynamic,dynamic> 为空
【发布时间】:2020-11-30 13:04:25
【问题描述】:

知道为什么我的货币映射在 CurrencyConverterState 类中为空吗?我正在将 API 中的货币加载到类 API 中的货币映射(请参阅类 API 的代码),并且还尝试在加载完成后设置状态。将 API 中的货币加载到我的货币地图后,我还可以从地图中访问汇率,这意味着我的地图工作正常且不为空。我通过打印货币汇率进行了测试,结果很好。但这仅适用于 API 类。问题是,一旦我在 CurrencyConverterState 类中测试我的货币地图,它就会说地图为空,并且我被困在循环进度指示器中(请参阅 CurrencyConverterState 类的代码)。我真的不知道为什么它说地图为空。任何帮助表示赞赏。

API 类代码:

class API 
{
  var fromTextController = new TextEditingController();

  Map<dynamic, dynamic> currencies;

  String fromCurrency;
  String toCurrency;

  String result;

  API(String from, String to){
    fromCurrency = from;
    toCurrency = to;
  }

  Future<dynamic> loadCurrencies() async {
    String uri = "http://api.openrates.io/latest";
    var response = await http
        .get(Uri.encodeFull(uri), headers: {"Accept": "application/json"});
    var responseBody = json.decode(response.body);
    Map curMap = responseBody['rates'];
    currencies = curMap;
    setState(() {});
    print (currencies["SEK"]);
  }


  Future<dynamic> doConversion() async {
    String uri =
        "http://api.openrates.io/latest?base=$fromCurrency&symbols=$toCurrency";
    var response = await http
        .get(Uri.encodeFull(uri), headers: {"Accept": "application/json"});
    var responseBody = json.decode(response.body);
    setState(() {
      result = (double.parse(fromTextController.text) *
          (responseBody["rates"][toCurrency]))
          .toString();
    });
    setState(() {});
    return "Success";
  }

  void setState(Null Function() param0) {}
}

CurrencyConverterState 类代码:

class CurrencyConverterState extends State<CurrencyConverter> {
  final API api = new API("USD", "SEK");

  CurrencyConverterState();

  int i = 1;

  @override
  void initState() {
    super.initState();
     api.loadCurrencies();
    api.fromTextController.addListener(doConversion);
    setState(() {

    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        resizeToAvoidBottomPadding: false,
        backgroundColor: Theme.of(context).primaryColor,
        body: api.currencies?.keys == null
            ? Center(child: CircularProgressIndicator())
            : Stack(children: [
                Positioned(
                  top: 30,
                  child: Container(
                    alignment: Alignment.center,
                    height: MediaQuery.of(context).size.height / 2,
                    width: MediaQuery.of(context).size.width,
                    child: Padding(
                      padding: const EdgeInsets.all(8.0),
                      child: Card(
                          elevation: 10,
                          child: Column(
                            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                            children: [
                              Text(
                                'Converter',
                                style: TextStyle(
                                    color: Colors.black, fontSize: 22.0),
                              ),
                              ListTile(
                                title: TextField(
                                  controller: api.fromTextController,
                                  decoration: InputDecoration(
                                      hintText: 'Enter a number'),
                                  style: TextStyle(
                                      fontSize: 20.0, color: Colors.black),
                                  keyboardType: TextInputType.numberWithOptions(
                                      decimal: true),
                                ),
                                trailing:
                                    buildDropDownButton(api.fromCurrency),
                              ),
                              ListTile(
                                title: Chip(
                                    label: api.result != null
                                        ? Container(
                                            width: 1000,
                                            height: 40,
                                            child: Text(
                                              api.result,
                                              style: Theme.of(context)
                                                  .textTheme
                                                  .headline4,
                                            ),
                                          )
                                        : Container(
                                            width: 1000,
                                            height: 40,
                                            child: Text(" "))),
                                trailing:
                                    buildDropDownButton(api.toCurrency),
                              ),
                            ],
                          )),
                    ),
                  ),
                ),
              ]));
  }

  Widget buildDropDownButton(String currencyCategory) {
    return DropdownButton(
        value: currencyCategory,
        dropdownColor: Colors.white,
        icon: Icon(Icons.arrow_downward),
        iconSize: 24,
        items: api.currencies.keys.map((dynamic value) => DropdownMenuItem(
                value: value,
                child: Row(children: <Widget>[
                  Text(value),
                ])))
            .toList(),
        onChanged: (dynamic value) {
          if (currencyCategory == api.fromCurrency) {
            api.fromCurrency = value;
          } else {
            api.toCurrency = value;
          }
          setState(() {});
        });
  }

  doConversion() {
    api.doConversion();
    setState(() {});
  }
}

【问题讨论】:

    标签: flutter dart setstate


    【解决方案1】:

    实际上,您是在检索货币之前检索它们,并且在检索它们时您永远不会更新 UI。

    这是一个可能的解决方案:

    //In API class
    Future<Map<String,dynamic>> loadCurrencies() async {
        String uri = "http://api.openrates.io/latest";
        var response = await http
            .get(Uri.encodeFull(uri), headers: {"Accept": "application/json"});
        var responseBody = json.decode(response.body);
        Map<String,dynamic> curMap = responseBody['rates'];
        print (currencies["SEK"]);
        return curMap;
    }
     
    

    然后在你的主类中使用 futureBuilder:

    return Scaffold(
            resizeToAvoidBottomPadding: false,
            backgroundColor: Theme.of(context).primaryColor,
            body: FutureBuilder(
               future: api.loadCurrencies(),
               builder: (context, currencies) =>{
                 return currencies==null?
                 ? Center(child: CircularProgressIndicator())
                 : Stack(/*rest of your code*/);
            })
    );
    

    【讨论】:

    • 记得投票给正面答案,这将有助于未来的读者了解如果遇到困难该怎么办
    • 我做到了,但因为我是新手并且声望低于 15,所以不会显示。
    猜你喜欢
    • 2021-09-25
    • 2018-12-01
    • 2019-12-19
    • 2019-02-10
    • 2020-05-02
    • 2021-07-14
    • 2021-04-13
    • 2021-08-05
    • 2020-01-10
    相关资源
    最近更新 更多